/***************************************************************************
 *   Copyright (C) 2004 by ian reinhart geiser                             *
 *   geiseri@kde.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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/

#include "specsupport.h"
#include "kdevproject.h"
#include "kdevmakefrontend.h"
#include "distpart_widget.h"

#include <kdebug.h>
#include <tdefiledialog.h>
#include <tdelocale.h>
#include <kprocess.h>
#include <tqfile.h>
#include <tqdir.h>
#include <tqerrormessage.h>
#include <tqregexp.h>
#include <tqpushbutton.h>
//#include <tqvbox.h>
#include <tqgroupbox.h>
#include <tqtabwidget.h>
#include <tqmessagebox.h>

/// \FIXME This is at least the fifth place in the tdevelop code something like this exists
TQString TQRegExp_escape(const TQString& str )
{
    return TQRegExp::escape(str);
}

SpecSupport::SpecSupport(DistpartPart *part) : packageBase(), m_part(part) {
	dir = "";

//     srcPackagePushButton = new TQPushButton(i18n("Src Package"),area());
//     buildAllPushButton = new TQPushButton(i18n("Src/Binary Packages"),area());
//     exportSPECPushButton = new TQPushButton(i18n("Export SPEC File"),area());
//     importSPECPushButton = new TQPushButton(i18n("Import SPEC File"),area());
//
//
//
//     connect(buildAllPushButton, TQT_SIGNAL(clicked()),
//             this, TQT_SLOT(slotbuildAllPushButtonPressed()));
//     connect(exportSPECPushButton, TQT_SIGNAL(clicked()),
//             this, TQT_SLOT(slotexportSPECPushButtonPressed()));
//     connect(importSPECPushButton, TQT_SIGNAL(clicked()),
//             this, TQT_SLOT(slotimportSPECPushButtonPressed()));
//     connect(srcPackagePushButton, TQT_SIGNAL(clicked()),
//             this, TQT_SLOT(slotsrcPackagePushButtonPressed()));

    parseDotRpmmacros();
}

SpecSupport::~SpecSupport() {
}

//    TQPushButton* buildAllPushButton;
void SpecSupport::slotbuildAllPushButtonPressed() {
    TQMap<TQString,TQString>::Iterator it;
    TQFile file1(dir + "/" + getAppSource());
    TQFile file2(*(map.find("_sourcedir")) + "/" + getAppSource());
    if (!file2.exists()) {
	if (!file1.exists()) {
	    TQMessageBox::critical(0 ,i18n("Error"),i18n("You need to create a source archive first."));
	    return;
	}
	else
            if (KDevMakeFrontend *makeFrontend = m_part->extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
                makeFrontend->queueCommand(dir,"cd " + TDEProcess::quote(dir) +
		" && cp " + TDEProcess::quote(getAppSource()) + " " + TDEProcess::quote(*(map.find("_sourcedir"))));
    }
    if (KDevMakeFrontend *makeFrontend = m_part->extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir,"cd " + TDEProcess::quote((((it = map.find("_specdir")) != map.end()) ? (*it) : dir)) +
		 " && rpmbuild -ba " + m_part->project()->projectName() + ".spec");
}

//    TQPushButton* exportSPECPushButton;
void SpecSupport::slotexportSPECPushButtonPressed() {
    TQMap<TQString,TQString>::Iterator it;
    TQString specname = ((it = map.find("_specdir")) != map.end()) ? (*it) : (m_part->project()->projectDirectory());
    specname += ("/" + m_part->project()->projectName() + ".spec");
    TQFile file(specname);

    if(file.open(IO_WriteOnly)) {
        TQTextStream stream(&file);
	stream << generatePackage();
        file.close();
    } else {
        kdDebug() << "TODO : intercept write error in SpecSupport::slotexportSPECPushButtonPressed()";
    }
}

TQString SpecSupport::getInfo(TQString s, TQString motif) {
    TQRegExp re(motif + "[ \t]*([^ \t].*[^ \t])[ \t]*");
    if (re.exactMatch(s))
        return re.cap(1);
    return TQString();
}

//    TQPushButton* importSPECPushButton;
void SpecSupport::slotimportSPECPushButtonPressed() {
       TQString fileName = KFileDialog::getOpenFileName(dir,"*.spec");
       if( fileName.isEmpty())
               return;
    TQFile file(fileName);

    if(file.open(IO_ReadOnly)) {
        TQTextStream stream(&file);

        while (!stream.atEnd()) {
            TQString s = stream.readLine();
            TQString info;
            if (!(info = getInfo(s,"Name:")).isEmpty())
                setAppName(info);
            else if (!(info = getInfo(s,"Version:")).isEmpty())
                setAppVersion(info);
            else if (!(info = getInfo(s,"Release:")).isEmpty())
                setAppRevision(info);
            else if (!(info = getInfo(s,"Vendor:")).isEmpty())
                setAppVendor(info);
            else if (!(info = getInfo(s,"Copyright:")).isEmpty())
                setAppLicense(info);
            else if (!(info = getInfo(s,"Summary:")).isEmpty())
                setAppSummary(info);
            else if (!(info = getInfo(s,"Group:")).isEmpty())
                setAppGroup(info);
            else if (!(info = getInfo(s,"Packager:")).isEmpty())
                setAppPackager(info);
            else if (s.startsWith("%description")) {
                TQString desc;
                while (!stream.atEnd()) {
                    TQString str = stream.readLine();
                    if (str.startsWith("%")) break;
                    else desc += str + "\n";
                }
                setAppDescription(desc);
            }
	    else if (s.startsWith("%changelog")) {
		TQString change;
		while (!stream.atEnd()) {
		    TQString str = stream.readLine();
		    if (str.startsWith("%")) break;
                    else change += str + "\n";
                }
		setAppChangelog(change);
            }
        }
    }
}

void SpecSupport::slotAddFileButtonPressed(){
TQString filename = KFileDialog::getOpenFileName ();
}

//    TQPushButton* srcPackagePushButton;
void SpecSupport::slotsrcPackagePushButtonPressed() {
    TQMap<TQString,TQString>::Iterator it;

    TQFile file1(dir + "/" + getAppSource());
    TQFile file2(*(map.find("_sourcedir")) + "/" + getAppSource());
    if (!file2.exists()) {
	if (!file1.exists()) {
	    TQMessageBox::critical(0,i18n("Error"),i18n("You need to create a source archive first."));
	    return;
	}
	else
            if (KDevMakeFrontend *makeFrontend = m_part->extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
	        makeFrontend->queueCommand(dir,"cd " + TDEProcess::quote(dir) +
		" && cp " + TDEProcess::quote(getAppSource()) + " " + TDEProcess::quote(*(map.find("_sourcedir"))));
    }
    if (KDevMakeFrontend *makeFrontend = m_part->extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir,"cd " + TDEProcess::quote((((it = map.find("_specdir")) != map.end()) ? (*it) : dir)) +
		 " && rpmbuild -bs " + m_part->project()->projectName() + ".spec");
}

void SpecSupport::parseDotRpmmacros() {
    TQFile dotfile(TQDir::homeDirPath() + "/.rpmmacros");

    if (!dotfile.open(IO_ReadOnly)) {
//        TQErrorMessage * msg = new TQErrorMessage(this);
//        msg->message("It seems you don't have a ~/.rpmmacros\nYou may experience problems building packages.\n");
//        msg->exec();
        return;
    }
    TQTextStream stream(&dotfile);

    // Perhaps will it appear as a necessity to parse the global rpm config file?

    // Pre defined macros :
    map.insert("name",getAppName());

    // .rpmmacros parsing :
    while (!stream.atEnd()) {
        TQString s = stream.readLine();
        TQRegExp re("%([^ \t]*)[ \t][ \t]*([^\t]*)$");
        if(re.exactMatch(s)) {
            TQRegExp subst("%\\{([^%]*)\\}");
            TQString value = re.cap(2).stripWhiteSpace();

            while(subst.search(value) != -1) {
                value.replace(TQRegExp("%\\{"+ TQRegExp_escape( subst.cap(1) ) +"\\}"),*map.find(subst.cap(1)));
            }
            map.insert(re.cap(1),value);
        }
    }
    dotfile.close();

    // create directories if necessary :
    createRpmDirectoryFromMacro("_topdir");
    createRpmDirectoryFromMacro("_tmppath");
    createRpmDirectoryFromMacro("_builddir");
    createRpmDirectoryFromMacro("_rpmdir");
    createRpmDirectoryFromMacro("_sourcedir");
    createRpmDirectoryFromMacro("_specdir");
    createRpmDirectoryFromMacro("_srcrpmdir");
}

bool SpecSupport::createRpmDirectoryFromMacro(const TQString & name) {
    TQMap<TQString,TQString>::Iterator it;
    if((it = map.find(name)) != map.end()) {
        TQDir dir(*it);
        if (!dir.exists()) return dir.mkdir(*it);
    }
    return false;
}

TQString SpecSupport::generatePackage( )
{
	TQString spec;
        spec += "# This spec file was generated by KDevelop \n";
        spec += "# Please report any problem to KDevelop Team <kdevelop-devel@kdevelop.org> \n";
        spec += "# Thanks to Matthias Saou for his explanations on http://freshrpms.net/docs/fight.html\n\n";

        spec += "Name: " + getAppName() + "\n";
        spec += "Version: " + getAppVersion() + "\n";
        spec += "Release: " + getAppRevision() + "\n";
        spec += "Vendor: " + getAppVendor() + "\n";
        spec += "Copyright: " + getAppLicense() + "\n";
        spec += "Summary: " + getAppSummary() + "\n";
        spec += "Group: " + getAppGroup() + "\n";
        spec += "Packager: " + getAppPackager() + "\n";
        spec += "BuildRoot:  %{_tmppath}/%{name}-root \n";
        spec += "Source: " + getAppSource() + "\n";

        spec += "\n";
        spec += "%description\n";
        spec += getAppDescription()+ "\n";

        spec += "\n";
        spec += "%prep\n";
        spec += "%setup\n";
        spec += "CFLAGS=\"$RPM_OPT_FLAGS\" CXXFLAGS=\"$RPM_OPT_FLAGS\" ./configure \\ \n";
        spec += "--target=" + getAppArch() + "\n";
	spec += "--disable-debug --enable-debug=no \n";

        spec += "\n";
        spec += "%build\n";
        spec += "%configure\n";
        spec += "make\n";

        spec += "\n";
        spec += "%install\n";
        spec += "rm -rf %{buildroot}\n";
        spec += "%makeinstall\n";

        spec += "\n";
        spec += "%clean\n";
        spec += "rm -rf %{buildroot}\n";

        spec += "\n";
        spec += "%post -p /sbin/ldconfig\n";

        spec += "%postun -p /sbin/ldconfig\n";

        spec += "%files\n";
        spec += "%defattr(-, root, root)\n";
        spec += "%doc AUTHORS COPYING ChangeLog NEWS README TODO\n";
        spec += "%{_bindir}/*\n";
        spec += "%{_libdir}/*.so.*\n";
        spec += "%{_datadir}/%{name}\n";
        spec += "%{_mandir}/man8/*\n";

        spec += "%changelog\n";
        spec += getAppChangelog() + "\n";

	return spec;
}