/*
* This file is part of QTGZManager, an open-source GUI for Slackware pkgtools.
* Copyright (C) 2006  Alexandre Albuquerque Arnt
*
* 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
*
* Contact e-mail : Alexandre Albuquerque Arnt <aaarnt@gmail.com>
* Program URL   : http://jtgzmanager.sf.net
*
*/
#include "package.h"
#include <QtCore>
#include <iostream>

#define DIR 					"/var/log/packages/"
#define FILELIST 	"FILE LIST:\n"

Package::Package() 
{
	targetDir = "";
	scanPackages = new QDir(PACKAGES_DIR);
	scanPackages->setFilter(QDir::Files);
	m_lPackages = scanPackages->entryList();

	//QDir a(QDir::homePath());
	//a.mkdir(PATH_TEMP);
}

Package::~Package() 
{
	delete scanPackages;
	m_lPackages.clear();
}

QString Package::getPackageBaseName( const QString& p ){

QString packageBaseName="";
QString verRest = "";
QString extra = "";
bool exitFunction = false;

int a = p.indexOf("-");

if (a<0) return packageBaseName;

packageBaseName = p.left(a);
verRest = p.mid(a+1);

for (int controller=1; controller<=10; controller++){
	exitFunction = false;

	for (int i=0; i < KNOWN_NAMES_LEN; i++){ 
		QString name = KNOWN_NAMES[i];
		if (packageBaseName.indexOf(name) >= 0){
			exitFunction = true;
			break;
		}	
	}

	if (exitFunction) break;
	
	if (verRest.indexOf(QRegExp("^[0-9]*[\\.\\-\\_]")) != -1) break; 

	a = verRest.indexOf("-");
	if (a>=0){
		extra = verRest.left(a);
		verRest = verRest.mid(a+1);	
	}	
	
	for (int i=0; i < KNOWN_ARCHS_LEN; i++){ 
		QString arch = KNOWN_ARCHS[i];	
		if (verRest.indexOf(arch) == 0){ //>= 0){
			exitFunction = true;
			break;	
		}
	}

	if (verRest == extra) break;
	packageBaseName = packageBaseName + "-" + extra;
	if (exitFunction) break;

	if (controller == 10){
		packageBaseName = "";
		break;
	}
}
return packageBaseName;
}

//Here, we do the URL html link tag addition
QString Package::makeURLClickable( const QString &s ){
	QString sb = s;

	QRegExp rx("((ht|f)tp(s?))://(\\S)+[^\"|)|(|.|\\s|\\n]");
	QRegExp rx1("^|[\\s]+(www\\.)(\\S)+[^\"|)|(|.|\\s|\\n]"); 
	rx.setCaseSensitivity( Qt::CaseInsensitive );
	rx1.setCaseSensitivity( Qt::CaseInsensitive );

	int search = 0;
	int ini = 0;

	//First we search for the 1st pattern: rx
	while ( (ini = rx.indexIn( sb, search )) != -1 ){
		QString s1 = rx.cap();
		QString ns = "<a href=\"" + s1 + "\">" + s1 + "</a>";
		sb.replace( ini, s1.length(), ns);
		search = ini + (2*s1.length()) + 15;	
	}

	search = 0;
	ini = 0;
	//Now, we search for the 2nd pattern: rx1
	while ( (ini = rx1.indexIn( sb, search )) != -1 ){
		QString s1 = rx1.cap();
		QString ns;
		if (s1[0] == '\n') ns += "\n";

		int blanks = s1.count(	QRegExp("^|[\\s]+") );
		for (int i=0; i<blanks; i++) ns += " ";

		ns += "<a href=\"http://" + s1.trimmed() + "\">" + s1.trimmed() + "</a>";
		sb.replace( ini, s1.length(), ns);
		search = ini + (2*s1.length()) + 15;	
	}

	sb.replace(QRegExp("\n"), "<br>");
	return sb;
}

// Regular expression for "http://" -> ^((ht|f)tp(s?))\://([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(/\S*)?$
QString Package::getInfoPackage( SelectedPackage sp, bool installed ){
	if ( installed == false ) {
    //"tar -Oxzf lives-0.9.8-i486-1gas.tgz install/slack-desc > slack-desc" 
    QProcess tar;
  
    QStringList args;
    args << "-Oxzf";
    args << sp.getCompleteFileName();
    args << "install/slack-desc";        
    tar.start("tar", args);
    if (!(tar.waitForStarted())) return "";
    if (!(tar.waitForFinished())) return "";
    QByteArray result = tar.readAll();
    
    QString pname = Package::getPackageBaseName(sp.getFileName());
    QString sb = result;
    
    QString t = pname + ":";
    //t = t.replace("\n", "");
    //t.concat(":");
    
    int x = sb.indexOf(t, 0);
   	if (x > 0) sb.remove(0, x);
   	
   	int begin=0;
   	x = sb.indexOf(t);
    while(x >= 0){        
   		if (x==0) sb.remove(x, x+t.length()+1);
   		else {
   			if (!sb.mid(x-1, x).contains("\\S")) sb.remove(x, (x+t.length()+1)-x);
   			else begin += pname.size();
   		}
    	x = sb.indexOf(t, begin);
    }	

		if ( !sb.isEmpty() ) return makeURLClickable(sb);
		else return 0;
	}
	else if ( installed == true ){
    QProcess tar;
    QStringList args;
  
    args << sp.getCompleteFileName();
    tar.start("cat", args);        
    if (!(tar.waitForStarted())) return "";
    if (!(tar.waitForFinished())) return "";
    QByteArray result = tar.readAll();
    
    QString pname = Package::getPackageBaseName(sp.getFileName());
    
		QString sb = result;  
    QString pkgSize;

		int y = sb.indexOf("UNCOMPRESSED PACKAGE SIZE", 0);
		if (y > 0) {
			y += 26;			
			while ( sb[y] != '\n' ){
				if ( sb[y].isDigit() ) pkgSize += sb[y];
				y++;
			}
		}
		if (!pkgSize.isEmpty()){
			bool ok;
			double d = pkgSize.toDouble( &ok );
			if ( ok == true ){
				if ( d > 1024 ){
					d /= 1024;
					pkgSize = QString::number( d, '.', 2 ) + " MB";
				}
				else pkgSize += " KB";
			} 				
		}

    QString t = pname + ":";
    //t = t.replace("\n", ""); 

    int x = sb.indexOf(t, 0);
  	if (x > 0) sb.remove(0, x);
      
    x = sb.indexOf("FILE LIST:", 0);
  	if (x > 0){
  		sb.remove(x, (sb.size()-1)-x);
   	}                      
   	
   	int begn=0;
   	x = sb.indexOf(t);
       
   	if (x == -1){
			if (pkgSize.isEmpty()) return "";
			else return QObject::tr("Installed size: %1").arg(pkgSize);
   	}
   		
   	while(x >= 0){        
   		if (x==0) sb.remove(x, (x+t.size()+1)-x);
   		else {
   			if (!sb.mid(x-1, x).contains("\\S")) sb.remove(x, (x+t.length()+1)-x);
   			else begn += pname.length();
   		}
     	x = sb.indexOf(t, begn);
    }	

		int z = sb.indexOf(QRegExp("[\\n]2+"), 0);
		if (z >= 0) sb.remove(z, sb.size()-z);
		//sb += "\n";
		if (!pkgSize.isEmpty()) sb += QObject::tr("Installed size: %1").arg(pkgSize);
		
		if ( !sb.isEmpty() ) return makeURLClickable(sb);
		else return 0;
	}
	
	return 0;
}

QString Package::showRegExp( const QString& a, const QString& re ){
	QRegExp rex(re);	
	QString res = rex.indexIn(a) > -1 ? rex.cap(0) : NO_MATCH;
	return res;
}

Result Package::verifyPackageInstallation( const QString& arq, const QStringList& frozenPackages ){       

  if (arq.endsWith(TGZ_PACKAGE_EXTENSION)){
    int i = m_lPackages.indexOf(arq.left(arq.length()-4));
    if (i != -1){
    	return(Result(INSTALLED, m_lPackages.value(i)));
    }
  }
	else if (arq.endsWith(RPM_PACKAGE_EXTENSION)){
    	return(Result(RPM, ""));
  }

	if ( frozenPackages.indexOf( QRegExp( Package::getPackageBaseName(arq)), 0 ) != -1){ 
		QString pattern =getPackageBaseName(arq);
		QString installedPackage = m_lPackages.filter( QRegExp(pattern) )[0];
		int i = m_lPackages.indexOf( QRegExp( installedPackage ) );
		return(Result(FROZEN, m_lPackages.value(i)));
	}
    
  Result res(NOT_INSTALLED, "");
  bool goAhead=false;
  
  QString res1 = showRegExp(arq, er);     
  if (res1 == NO_MATCH) {
    return Result(INTERNAL_ERROR, "");                
  }

	QStringList lPackages2 = m_lPackages.filter( QRegExp( getPackageBaseName( arq )) );

  foreach ( QString pacote, lPackages2 ){      
    if ((arq == ".") || (arq == "..")) continue;        
               
    QString res2 = showRegExp(pacote, er3);

    int a = res1.indexOf(res2);        
    if (a == 0){
      //It must first make the "brake string" test... 
      QStringList c = arq.split("-");
      QStringList d = pacote.split("-");

      if ((c.size() != 0) && (d.size() != 0) && (c.size() == d.size())){
        goAhead=true;
        for (int k = 0; k < c.size()-3; k++) {
	        if (c[k] != (d[k])) goAhead = false;  
        }

        if (goAhead){
          QString st1(c[c.size()-3]);
          QString st2(d[c.size()-3]);
          
          QStringList ver1 = st1.split(QRegExp("[._]"));
          QStringList ver2 = st2.split(QRegExp("[._]"));
          
          //if (((ver1.size()==1) && (ver1[0] == st1)) || ((ver2.size()==1) && (ver2[0] == st2))){
          //  return Result(INTERNAL_ERROR, "");
          //}
                  
          bool bVer1Alpha=false, bVer2Alpha=false;                  
                  
          foreach (QString x, ver1){
            if (x.indexOf(QRegExp("[a-zA-Z]")) != -1){
              bVer1Alpha = true; 
            }
          }
          
          foreach (QString x, ver2){
            if (x.indexOf(QRegExp("[a-zA-Z]")) != -1){
              bVer2Alpha = true; 
            }
          }
 
          //Shall we make the version test?
     		  if (bVer1Alpha && bVer2Alpha) {
     			  QString s1 ="", s2="";
     			  
     			  foreach (QString aux, ver1) s1 = s1 + aux;
     			  foreach (QString aux, ver2) s2 = s2 + aux;
     			  
     			  int comp = s1.compare(s2, Qt::CaseInsensitive);
     			  if (comp > 0) {
    					  return Result(SUPERIOR_VERSION, pacote);
     			  }
     			  else if (comp < 0){
     				  return Result(INFERIOR_VERSION, pacote);
     			  }
     			  else if (comp == 0){
							goAhead = true;							
						}
     		  }	  
     		  
					else if (bVer1Alpha != bVer2Alpha){  
						goAhead = false;
     			  QString s1="", s2="";
     			  foreach (QString aux, ver1) s1 = s1 + aux;
     			  foreach (QString aux, ver2) s2 = s2 + aux;	        			  

						int comp = s1.compare(s2, Qt::CaseInsensitive);

						if ( comp > 0 )
							return Result ( SUPERIOR_VERSION, pacote );
						else if ( comp < 0 )
							return Result ( INFERIOR_VERSION, pacote );	
					} 
					
					else if (!bVer1Alpha && !bVer2Alpha){ 
     			  //QString s1="", s2="";
						//foreach (QString aux, ver1) s1 = s1 + aux;
     			  //foreach (QString aux, ver2) s2 = s2 + aux;	        			  
						
						if (ver1.size() != ver2.size()) {
							if (ver1.size() > ver2.size()){
								int sub = ver1.size()-ver2.size();
								for(int a=0; a<sub; a++) ver2 << "0";
							}
							else {
								int sub = ver2.size()-ver1.size();
								for(int a=0; a<sub; a++) ver1 << "0";	
							}
						}

						for(int a=0; a<ver1.size(); a++){						
							bool equal = ver1[a].toInt() == ver2[a].toInt();						
							if ( equal == true ) continue;

							bool comp = ver1[a].toInt() > ver2[a].toInt();
							if ( comp == true )
								return Result ( SUPERIOR_VERSION, pacote );
							else if ( comp == false )
								return Result ( INFERIOR_VERSION, pacote );	
						}
					}	


          if (goAhead){
            int n1=0, n2=0;	        			  
     			  
     			  QString s1="", s2="";
     			  foreach (QString aux, ver1) s1 = s1 + aux;
     			  foreach (QString aux, ver2) s2 = s2 + aux;	        			  
     			  int comp = s1.compare(s2, Qt::CaseInsensitive);
     			  bool equal = (comp == 0);
     			  
    				//We must take care with diverse releases of the same package (the final number).
     			  if (equal) {
							//We must make the platform test 
	     			  comp = c[c.size()-2].compare(d[c.size()-2], Qt::CaseInsensitive);
  	   			  equal = (comp == 0);							

							if (equal){
								//Here comes the release test!
								c[c.size()-1] = c[c.size()-1].replace(TGZ_PACKAGE_EXTENSION, "");
								//else c[c.size()-1] = c[c.size()-1].replace(RPM_PACKAGE_EXTENSION, "");

								QString sn1, sn2;
								sn1 = showRegExp(c[c.size()-1], "[1-9]*");
								sn2 = showRegExp(d[c.size()-1], "[1-9]*");
	
   					  	bool ok1, ok2;
              	n1 = /*c[c.size()-1]*/ sn1.toInt(&ok1);
              	n2 = /*d[c.size()-1]*/ sn2.toInt(&ok2);
              	if (!(ok1) || !(ok2)) break; 
               
   					  	if (n1 > n2){	        				  
   					  	  return Result(SUPERIOR_VERSION, pacote);
     				  	}		        				  
     				  	else if (n1 < n2){
     					  	return Result(INFERIOR_VERSION, pacote);
     					  }	
								else if (n1 == n2){
									return Result(INSTALLED, pacote);
								}
     			  	}
							else{
								if (comp > 0) return Result(SUPERIOR_VERSION, pacote);
								else return Result(INFERIOR_VERSION, pacote);
							}
						}
            else if (!(equal)) {
 				  	  if (s1.size() != s2.size()){
 				  		  if (s1.size() < s2.size()){
 				  			  for(int j=0; j<s2.size()-s1.size(); j++){
 				  				  s1 = s1 + "0";
 				  				  //if (comp < 0) s1 = "0".concat(s1);
 				  				  //else if (comp > 0) s1 = s1.concat("0");
 				  			  }
 				  		  }
 				  		  else{
 				  			  for(int j=0; j<s1.size()-s2.size(); j++){
 				  				  s2 = s2 + "0";
 				  				  //if (comp < 0) s2 = (s2).concat("0");
 				  				  //else if (comp > 0) s2 = "0".concat(s2);
 				  			  }
 				  		  }	        				  		  
 				  		  
 	        		  comp = s1.compare(s2, Qt::CaseInsensitive);
 				  	  }
 				  	  
 				  	  if (comp > 0){
 				  		  return Result(SUPERIOR_VERSION, pacote);
 					    }		        				  
 					  
 					
 					    else if (comp < 0){
 						    return Result(INFERIOR_VERSION, pacote);
	            }	        				  
	          }	  
	        }	  
	      }
	    }
    }
	}        
  
  return res; 						
}

void Package::setTargetDir( const QString &td ){
  targetDir = td;
}

QStringList Package::getPackageContents( const QString& pkgName, bool installed ){
  FILE *file;
  char linebuf[1024];
  QString st, fn; 
	QStringList sl;	

	if ( installed )
	{
		fn = pkgName;
		file = fopen ( QFile::encodeName ( fn ),"r" );
		if ( file )
		{
			while ( fgets ( linebuf,sizeof ( linebuf ),file ) )
			{
				if ( !strcmp ( linebuf,FILELIST ) )
				{
					break;
				}
			}
			while ( fgets ( linebuf,sizeof ( linebuf ),file ) )
			{
				st = "/";
				st += linebuf;
				st.truncate ( st.length() -1 );
				if ( st.left ( 8 ) != "/install" && st.left ( 3 ) != "/./" )
				{
					sl << st;
				}
			}
			fclose ( file );
		}
	}
	else
	{
		QProcess tar;
	
		QStringList args;
		args << "-Otf";
		args << pkgName;
		tar.start ( "tar", args );
		if ( ! ( tar.waitForStarted() ) ) return QStringList();
		if ( ! ( tar.waitForFinished() ) ) return QStringList();
		QByteArray result = tar.readAllStandardError(); 
	
		QString aux(result);
		QStringList rsl = aux.split("\n", QString::SkipEmptyParts);
		
		if ( !rsl.isEmpty() ){
			rsl.removeFirst();
			rsl.replaceInStrings(QRegExp("^"), "/");
			rsl.sort();
		}
		
		return rsl;
	}
	
	sl.sort();
	return sl;
}	

QMap<QString, QStringList> Package::findFile( const QString& name )
{
  FILE *file;
  char linebuf[1024];
  QString st;
  QString fn, dr = DIR;
	QMap<QString, QStringList> m;
  
  QDir d(DIR);
	if ( d.exists() )
	{
		const QFileInfoList list = d.entryInfoList();
		foreach ( QFileInfo fi, list )
		{
			if ( !fi.isDir() && fi.isReadable() )
			{
				fn = dr + fi.fileName();
				file = fopen ( QFile::encodeName ( fn ),"r" );
				if ( file )
				{
					QStringList sl;
					while ( fgets ( linebuf,sizeof ( linebuf ),file ) )
					{
						if ( !strcmp ( linebuf,FILELIST ) )
						{
							break;
						}
					}
					while ( fgets ( linebuf,sizeof ( linebuf ),file ) )
					{
						if ( QString::fromLocal8Bit ( linebuf ).indexOf ( name ) != -1 )
						{
							st = "/";
							st += linebuf;
							st.truncate ( st.length() -1 );
							if ( st.left ( 8 ) != "/install" )
							{
								m.insert(fi.fileName(), sl << st);
							}
						}
					}
					fclose ( file );
				}
			}
		}
	}
	return m;
}
