// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#include "ProjectFileManager.h"
#include "SysCall.h"

#include <fstream>

void ProjectFileManager::addPath(const char *source, const char *destination) {
  _manager.addPath(source, destination);
} 

const char *ProjectFileManager::src(long n) const {
  return _manager.src(n);
}

const char *ProjectFileManager::dest(long n) const {
  return _manager.dest(n);
}

bool ProjectFileManager::isNewer (const char *file) const {
  time_t last_modified_src;
  if (!SysCall::file_modification_time(file, last_modified_src))
    return false;

  // determine the destination path of the file
  Puma::ProjectFile::MapConstIter iter;
  if (!_manager.isBelow (file, iter)) {
    assert (false); // if we came here, the file should be registered
    return false;
  }

  Puma::ProjectFile &project_file = (Puma::ProjectFile&)iter->second;
  Puma::Filename dest = project_file.dest ();
  if (!dest.is_defined ()) {
    // determine the destination path
    std::ostringstream path;
    if (!getDestinationPath (file, path))
      return false;
    std::string dest_path = path.str ();
    project_file.dest (dest_path.c_str ());
    dest = project_file.dest ();
  }

  bool newer = true;
  time_t last_modified_dest;
  if (SysCall::file_modification_time(dest.name(), last_modified_dest))
    if (last_modified_src <= last_modified_dest)
      newer = false;

  return newer;
}


// save an opened file to its destination
void ProjectFileManager::save (const char *name, bool is_modified, const char *content) const {

  // Do not write files to protected paths or files from outside the
  // source directories.
  if (_manager.isProtected (name))
    return;

  // determine the destination path of the file
  MapConstIter iter;
  if (!isBelow (name, iter)) {
    assert (false); // if we came here, the file should be registered
    return;
  }

  Puma::ProjectFile &project_file = (Puma::ProjectFile&)iter->second;
  Puma::Filename dest = project_file.dest ();
  if (!dest.is_defined ()) {
    // determine the destination path
    std::ostringstream path;
    if (!getDestinationPath (name, path))
      return;
    std::string dest_path = path.str ();
    project_file.dest (dest_path.c_str ());
    dest = project_file.dest ();
  }

  // make sure that the directory for the file exists
  if (!SysCall::make_directory_hierarchy (dest.path()))
    return;

  // Check whether the file has to be updated.
  if (isNewer(name) || is_modified) {
    // Write the file to disk.
    char *file = (char*)dest.name ();
    std::ofstream out (file, std::ios::out);
    out << content;
  }

}
