// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2004  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 "CCompiler.h"
#include "System.h"
#include "regex.h"

//Puma includes
#include "Puma/VerboseMgr.h"
#include "Puma/PathManager.h"
using namespace Puma;

bool CCompiler::execute(){
	
	VerboseMgr vm(cout,_config.verbose());
	vm << "Compiling" << endvm;

	bool status=true;
	
	if ( _config.make_dep() ){
		vm++;
		vm << "Creating dependencies" <<endvm; 
		return make_dep();
	}
	
	status=compile();
	
	// if we don't want acc files remove them
	if (! _config.keep_acc() ){
		vm++;
		vm << "Removing intermediate .acc files" <<endvm;
		remove_acc();
	}
	
	return status;
}
	
	

	
	

bool CCompiler::make_dep(){
	AGxxConfig::FileCont::iterator file = _config.proj_paths().begin();
	
	// if there were no aspect headers in command string
	// search all aspect headers in all project paths
	if(_config.ah_files().empty()){
		
		PathManager path(this->_err);
		
		while(file != _config.proj_paths().end()){
			path.addPath(file->c_str());
			file++;
		}
		
		PathIterator ah_iter (".*\\.ah$");
		char* ah_file;
		while ( (ah_file=(char*)path.iterate(ah_iter))){
			_config.ah_files().push_back(ah_file);	
		}
	}
	
	/*
	* setup execution string for gcc
	*/
	string exec_str = "\""+_config.cc_bin()+"\"";
	
	file = _config.ah_files().begin();
	
	OptionVec::iterator opt = _config.optvec().begin();
	while(opt != _config.optvec().end()){
		// find all g++ options and files
		switch(opt->flag() & (OptionItem::OPT_GCC | OptionItem::OPT_FILE)){
			case OptionItem::OPT_GCC:
				exec_str.append(" "+opt->name()+opt->arg());
				break;
			case OptionItem::OPT_FILE:
				
				// explicitly include all aspect headers (for creating dependency information)
				//this is only executed once, as 'file' iterator is not reseted 
				while(file != _config.ah_files().end()){
					exec_str+= " -include \""+*file+"\"";
					file++;
				}
				
				exec_str.append(" \""+opt->name()+"\"");
				
				// explicitly include all aspect headers (for creating dependency information)
				//this is only executed once, as 'file' iterator is not reseted 
				while(file != _config.ah_files().end()){
					exec_str+= " -include \""+*file+"\"";
					file++;
				}
				break;
		}
		opt++;
	}
	
	
	// execute gcc
	System gcc(_err,_config,exec_str);
	return gcc.execute();
}

bool CCompiler::compile(){

	// construct execution string 
	string exec_str = "\""+_config.cc_bin()+"\"";


	OptionVec::iterator opt = _config.optvec().begin();
	while(opt != _config.optvec().end()){
		// find all g++ options and files
		if(opt->flag() & OptionItem::OPT_GCC){
				exec_str.append(" "+opt->name()+opt->arg());
		}
		//weaved files
		else if(opt->flag() & ( OptionItem::OPT_FILE_ACC^OptionItem::OPT_FILE)){
			// explictly mark .acc files  as c++ files
			exec_str.append(" -xc++ \""+opt->name()+"\" -xnone");
		}
		else if(opt->flag() & (OptionItem::OPT_FILE_GCC^OptionItem::OPT_FILE)){
			exec_str.append(" \""+opt->name()+"\" ");
			// specify output file in front of inputs
		}
		opt++;
	}
	if (! _config.output_file().empty()){
		exec_str.append( " -o \""+_config.output_file()+"\"");
	}
				
	// execute compiler
	System gcc(_err,_config,exec_str);
	return gcc.execute();
}
	
void CCompiler::remove_acc(){
	OptionVec::iterator opt = _config.optvec().begin();
	while(opt != _config.optvec().end()){
		if( opt->flag() != ( OptionItem::OPT_FILE_ACC|OptionItem::OPT_FILE_GCC)){
			++opt;
			continue;
		}
		// check if removal succeeded
		string rm_file(opt->name());
		if(remove(rm_file.c_str()) < 0){
			this->_err << sev_warning << "Couldn't remove " << rm_file.c_str() << endMessage;
		}
		++opt;
	}

}

