/***************************************************************************
 *   Copyright (C) 2008 by Tim McCormick 				   *
 *   tim@pcbsd.org   						  	   *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

#include <sys/types.h>
#include <sys/sysctl.h>

#include <QRegExp>
#include <QString>
#include <QStringList>
#include <QFile>
#include <QTextStream>
#include <QProcess>
#include <QCoreApplication>
#include <QDebug>

#include <QObject>

#include "pcbsd-utils.h"

#include "../../config.h"

using namespace pcbsd;

QString Utils::getConfFileValue( QString oFile, QString Key )
{
   return getConfFileValue(oFile, Key, 1);
}

QString Utils::getConfFileValue( QString oFile, QString Key, int occur )
{
	int found = 1;
    
    	QFile file( oFile );
    	if ( ! file.open( QIODevice::ReadOnly ) ) {
		return QString();
	}

       	QTextStream stream( &file );
       	QString line;
       	while ( !stream.atEnd() ) {
            	line = stream.readLine(); // line of text excluding '\n'
		line = line.section("#",0,0).trimmed(); //remove any comments
		if(line.isEmpty()){ continue; }
		int index = line.indexOf(Key, 0);
                //qDebug() << "Line:" << line << index;
                // If the KEY is not found at the start of the line, continue processing 
		if(index!=0)
			continue;
		
	    	if ( found == occur) {
 			line.remove(line.indexOf(Key, 0), Key.length());
    
    			// Remove any quotes
   			if ( line.indexOf('"') == 0 )
				line = line.remove(0, 1);
    
    			if ( line.indexOf('"') != -1  )
				line.truncate(line.indexOf('"'));

			file.close();
			
    			return line;
    		} else {
       			found++;  
    		}
        }

	file.close();
	return QString();
}

QString Utils::getConfFileValue( QString oFile, QString Key, QString ValRx, int occur )
{
	int found = 1;
    
    	QFile file( oFile );
    	if ( ! file.open( QIODevice::ReadOnly ) ) {
		return QString();
	}

	QString rxStr ( Key );
	rxStr.append( ValRx );
	QRegExp rx(rxStr);
       	QTextStream stream( &file );
       	QString line;
       	while ( !stream.atEnd() ) {
            	line = stream.readLine(); // line of text excluding '\n'
            
                // If the KEY is not found in the line, continue processing 
		if ( line.trimmed().indexOf("#", 0) == 0 || line.indexOf(rx, 0) == -1 || line.indexOf(rx, 0) > 0)
			continue;

	    	if ( found == occur ) {
 			line.remove(line.indexOf(Key, 0), Key.length());
    
    			// Remove any quotes
   			if ( line.indexOf('"') == 0 )
				line = line.remove(0, 1);
    
    			if ( line.indexOf('"') != -1  )
				line.truncate(line.indexOf('"'));

			file.close();
    			return line;
    		} else {
       			found++;  
    		}
        }

	file.close();
	return QString();
}

bool Utils::setConfFileValue( QString oFile, QString oldKey, QString newKey )
{
	return setConfFileValue(oFile, oldKey, newKey, -1);
}

bool Utils::setConfFileValue( QString oFile, QString oldKey, QString newKey, int occur )
{
    	// Lets the dev save a value into a specified config file. 
	// The occur value tells which occurance of "oldKey" to replace
    	// If occur is set to -1, it will remove any duplicates of "oldKey"
    
	//copy the original file to create a temporary file for editing
	QString oFileTmp = oFile + ".tmp";
	QString cmd = "cp "+oFile+" "+oFileTmp;
	runShellCommand(cmd);
	
	//Continue evaluating the temporary file
    	QStringList SavedFile;
    	int found = 1;

    	// Load the old file, find the oldKey, remove it and replace with newKey
    	QFile file( oFileTmp );
	if ( ! file.open( QIODevice::ReadOnly ) )
		return false;

        QTextStream stream( &file );
        QString line;
        while ( !stream.atEnd() ) {
        	line = stream.readLine(); // line of text excluding '\n'
            
		// Key is not found at all
		if ( line.indexOf(oldKey, 0) == -1 ) {
	        	SavedFile << line ;
			continue;
		}

		// Found the key, but it is commented out, so don't worry about this line
		if ( line.trimmed().indexOf("#", 0) == 0 ) {
	         	SavedFile << line ;
			continue;
		}

		// If the KEY is found, and we are just on wrong occurance, save it and continue to search  
		if ( occur != -1 && found != occur ) {
	         	SavedFile << line ;
			found++;
			continue;
		}

            	// If the KEY is found in the line and this matches the occurance that must be processed
            	if ( ! newKey.isEmpty() && found == occur )
           	{
	         	SavedFile << newKey ;
			newKey.clear();
	    		found++;
			continue;
            	} 

             	// If the KEY is found and we just want one occurance of the key
            	if ( occur == -1 && ! newKey.isEmpty() ) {
	         	SavedFile << newKey ;
			newKey.clear();
			found++;	
			continue;
		}

        }

   	file.close();

	// Didn't find the key? Write it!
	if ( ! newKey.isEmpty() )
	    SavedFile << newKey;
	
    
    	// Save the new file
    	QFile fileout( oFileTmp );
    	if ( ! fileout.open( QIODevice::WriteOnly ) )
		return false;

  	QTextStream streamout( &fileout );
	for (int i = 0; i < SavedFile.size(); ++i)
          	streamout << SavedFile.at(i) << "\n";

       	fileout.close();

	//Have the temporary file with new changes overwrite the original file
	cmd = "mv "+oFileTmp+" "+oFile;
	runShellCommand(cmd);	
	
	return true;
    
}

QStringList Utils::runShellCommand( QString command ){
  //Just a simple overload for backwards compatibility
  bool junk = false;
  return runShellCommand(command,junk);	
}

//Run a shell command (return a list of lines and an optional success flag)
QStringList Utils::runShellCommand( QString command , bool& success)
{
 //split the command string with individual commands seperated by a ";" (if any)
 QStringList cmdl = command.split(";");
 QString outstr;
 //run each individual command
 bool ok = true;
 for(int i=0;i<cmdl.length() && ok;i++){ 
   QProcess p;  
   //Make sure we use the system environment to properly read system variables, etc.
   p.setProcessEnvironment(QProcessEnvironment::systemEnvironment());
   //Merge the output channels to retrieve all output possible
   p.setProcessChannelMode(QProcess::MergedChannels);   
   p.start(cmdl[i]);
   while(p.state()==QProcess::Starting || p.state() == QProcess::Running){
     p.waitForFinished(200);
     QCoreApplication::processEvents();
   }
   QString tmp = p.readAllStandardOutput();
   outstr.append(tmp);
   ok = (p.exitCode()==0);
 }
 if(outstr.endsWith("\n")){outstr.chop(1);} //remove the newline at the end 
 QStringList out = outstr.split("\n");
  //if(success!=0){
    //Also return this optional output
    success = ok;
   //}
 //qDebug() << command;
 //for(int j=0; j<out.length();j++){ qDebug() << out[j];}
 return out;
}


