/***************************************************************************
 *   Copyright (C) 2004 by Predrag Viceic                                  *
 *   viceic@net2000.ch                                            *
 *                                                                         *
 *   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 "projectmanager.h"

ProjectManager::ProjectManager(SoundManager* sm, EnvelopeData* ed,QObject *parent, const char *name)
 : QObject(parent, name)
{
    soundManager=sm;
    effectFrame=0;
    envelopeData=ed;
    leftLoopMarker=0;
    rightLoopMarker=0;
    filename="";
}


ProjectManager::~ProjectManager()
{
}




/*!
    \fn ProjectManager::saveWaveBuffers()
 */
QStringList ProjectManager::saveWaveBuffers()
{
    QStringList names;
    if(soundManager!=0 && soundManager->hasSound()){
        QString tempDir=soundManager->getTempDir()+"/"+QFileInfo(filename).baseName();
        QString name=tempDir;
        QFile orig_wavefile(name.append("/orig-wave.").append(soundManager->getFileExtension()));
        cout<<"Writing wave to: "<<orig_wavefile.name()<<"\n";
        if (orig_wavefile.exists()) orig_wavefile.remove();
        soundManager->saveChunkToAs(orig_wavefile.name(),
                                    0,
                                    soundManager->getFrames(),
                                    soundManager->toBpsCode(32),0,SoundHolder::ORIGINAL_WAVE);

        names.append(orig_wavefile.name());
        if(effectFrame!=0){
            name=tempDir;
            QFile ladspa_wavefile(name.append("/ladspa-wave.").append(soundManager->getFileExtension()));
            cout<<"Writing wave to: "<<ladspa_wavefile.name()<<"\n";
            if (ladspa_wavefile.exists()) ladspa_wavefile.remove();
            soundManager->saveChunkToAs(ladspa_wavefile.name(),
                                        0,
                                        soundManager->getFrames(),
                                        soundManager->toBpsCode(32),0,SoundHolder::AFTER_LADSPA);
            names.append(ladspa_wavefile.name());
        }
        name=tempDir;
        QFile envelope_wavefile(name.append("/env-wave.").append(soundManager->getFileExtension()));
        cout<<"Writing wave to: "<<envelope_wavefile.name()<<"\n";
        if (envelope_wavefile.exists()) envelope_wavefile.remove();
        soundManager->saveChunkToAs(envelope_wavefile.name(),
                                    0,
                                    soundManager->getFrames(),
                                    soundManager->toBpsCode(32),0,SoundHolder::AFTER_ENVELOPE);
        names.append(envelope_wavefile.name());
    }
    return names;
}


/*!
    \fn ProjectManager::saveProject()
 */
void ProjectManager::saveProject()
{
    cout<<"Filename: "<<filename<<"\n";
    filename.replace(".frc.tgz","");
    QString tempDir=soundManager->getTempDir()+"/"+QFileInfo(filename).baseName();
    QDir dir(tempDir);
    dir.mkdir(tempDir);
    
    FileManager::purgeDir(tempDir);
    
    QStringList wavefilenames=saveWaveBuffers();
    QDomDocument d;
    QDomElement freecycle_project=d.createElement("freecycle");
    d.appendChild(freecycle_project);

    QDomAttr releaseAttr=d.createAttribute("release");
    releaseAttr.setValue(QString(RELEASE_NO));
    freecycle_project.setAttributeNode(releaseAttr);
    
    QDomAttr bpmModifierAttr=d.createAttribute("bpm-modifier");
    bpmModifierAttr.setValue(bpmModifier);
    freecycle_project.setAttributeNode(bpmModifierAttr);

    if(leftLoopMarker && rightLoopMarker){
        freecycle_project.appendChild(loopMarkersToXML(leftLoopMarker, rightLoopMarker));
    }


    if(envelopeData!=0)
        freecycle_project.appendChild(envelopeToXML(envelopeData));
    if(lockedBeatLines.count()>0)
        freecycle_project.appendChild(lockedBLToXML(lockedBeatLines));
    if(effectFrame!=0)
        freecycle_project.appendChild(ladspaToXML(effectFrame));
    if(lockedBeatRects.count()>0){
        freecycle_project.appendChild(stacksToXML(lockedBeatRects));
        saveStackElementWaves(tempDir,lockedBeatRects);
    }

    QString projectfilename=tempDir;
    QFile file(projectfilename.append("/project.xml"));
    cout<<"project filename: "<<file.name()<<"\n";
    if (file.exists()) file.remove();
    file.open(IO_WriteOnly);
    QTextStream s( &file);
    s<<d;
    file.close();

    QProcess proc(this);

    dir.cdUp();
    QFileInfo finfo(filename);

    QFile savefile(filename+".frc.tgz");
    if(savefile.exists()) savefile.remove();

 

    proc.addArgument("tar");
    proc.addArgument("czf");
    proc.addArgument(savefile.name());
    proc.addArgument("-C");
    proc.addArgument(dir.path()+"/");
    proc.addArgument(QFileInfo(filename).baseName()+"/");
    cout<<"Executing "<<proc.arguments().join(" ")<<"\n";



    proc.start();
    while(proc.isRunning()) sleep(10);
    
    FileManager::deleteDir(tempDir);





}


/*!
    \fn ProjectManager::setFilename(QString fn)
 */
void ProjectManager::setFilename(QString fn)
{
    filename=fn;
}


/*!
    \fn ProjectManager::setLockedBeatLines(QValueList<beatline_data> lbd)
 */
void ProjectManager::setLockedBeatLines(QValueList<beatline_data> lbd)
{
    
    lockedBeatLines.clear();
    lockedBeatLines=lbd;
}


/*!
    \fn ProjectManager::envelopeToXML(EnvelopeData* envData)
 */
QDomNode ProjectManager::envelopeToXML(EnvelopeData* envData)
{
    QDomDocument d;
    QDomElement envDom=d.createElement("envelope");
    d.appendChild(envDom);
    QDomAttr attackAttr=d.createAttribute("attack");
    attackAttr.setValue(QString::number(envData->attack));
    envDom.setAttributeNode(attackAttr);

    QDomAttr attackCXAttr=d.createAttribute("attackCx");
    attackCXAttr.setValue(QString::number(envData->attackC.x()));
    envDom.setAttributeNode(attackCXAttr);

    QDomAttr attackCYAttr=d.createAttribute("attackCy");
    attackCYAttr.setValue(QString::number(envData->attackC.y()));
    envDom.setAttributeNode(attackCYAttr);

    QDomAttr holdAttr=d.createAttribute("hold");
    holdAttr.setValue(QString::number(envData->hold));
    envDom.setAttributeNode(holdAttr);

    QDomAttr decayAttr=d.createAttribute("decay");
    decayAttr.setValue(QString::number(envData->decay));
    envDom.setAttributeNode(decayAttr);

    QDomAttr decayCXAttr=d.createAttribute("decayCx");
    decayCXAttr.setValue(QString::number(envData->decayC.x()));
    envDom.setAttributeNode(decayCXAttr);

    QDomAttr decayCYAttr=d.createAttribute("decayCy");
    decayCYAttr.setValue(QString::number(envData->decayC.y()));
    envDom.setAttributeNode(decayCYAttr);

    QDomAttr sustainAttr=d.createAttribute("sustain");
    sustainAttr.setValue(QString::number(envData->sustain));
    envDom.setAttributeNode(sustainAttr);

    QDomAttr releaseAttr=d.createAttribute("release");
    releaseAttr.setValue(QString::number(envData->release));
    envDom.setAttributeNode(releaseAttr);

    QDomAttr releaseCXAttr=d.createAttribute("releaseCx");
    releaseCXAttr.setValue(QString::number(envData->releaseC.x()));
    envDom.setAttributeNode(releaseCXAttr);

    QDomAttr releaseCYAttr=d.createAttribute("releaseCy");
    releaseCYAttr.setValue(QString::number(envData->releaseC.y()));
    envDom.setAttributeNode(releaseCYAttr);



    QDomAttr durationAttr=d.createAttribute("duration");
    durationAttr.setValue(QString::number(envData->getDuration()));
    envDom.setAttributeNode(durationAttr);

    QDomAttr resolutionAttr=d.createAttribute("resolution");
    resolutionAttr.setValue(QString::number(envData->getResolution()));
    envDom.setAttributeNode(resolutionAttr);

    QDomAttr modeAttr=d.createAttribute("mode");
    modeAttr.setValue(QString::number(envData->getMode()));
    envDom.setAttributeNode(modeAttr);

    QDomAttr activeAttr=d.createAttribute("active");
    activeAttr.setValue(QString::number(envData->isEnabled()));
    envDom.setAttributeNode(activeAttr);

    return d;
}


/*!
    \fn ProjectManager::lockedBLToXML(QValueList <beatline_data> lockedBL)
 */
QDomNode ProjectManager::lockedBLToXML(QValueList <beatline_data> lockedBL)
{
    QDomDocument d;
    QDomElement beatlinesDom=d.createElement("beatlines");
    d.appendChild(beatlinesDom);

    for (uint i=0;i<lockedBL.count();i++){
        QDomElement beatlineE=d.createElement("beatline");
        QDomAttr lockedAttr=d.createAttribute("locked");
        lockedAttr.setValue("1");
        beatlineE.setAttributeNode(lockedAttr);
        
        
        QDomAttr positionAttr=d.createAttribute("position");
        positionAttr.setValue(QString::number(lockedBL[i].position));
        beatlineE.setAttributeNode(positionAttr);
        if(lockedBL[i].midiNote!=-1){
            QDomAttr midiAttr=d.createAttribute("midiNote");
            midiAttr.setValue(QString::number(lockedBL[i].midiNote));
            beatlineE.setAttributeNode(midiAttr);
        }
        beatlinesDom.appendChild(beatlineE);
    }
    return d;
}


/*!
    \fn ProjectManager::ladspaToXML(EffectFrame* ef)
 */
QDomNode ProjectManager::ladspaToXML(EffectFrame* ef)
{
    QDomDocument d;
    QDomElement ladspaDom=d.createElement("ladspa");
    d.appendChild(ladspaDom);

    LADSPAEffect* ladspa=ef->getLadspa();

    QDomAttr uidAttr=d.createAttribute("uid");
    uidAttr.setValue(QString::number(ladspa->getUniqueID()));
    ladspaDom.setAttributeNode(uidAttr);

    QDomAttr nameAttr=d.createAttribute("name");
    nameAttr.setValue(ladspa->getName());
    ladspaDom.setAttributeNode(nameAttr);

    QDomAttr doubleAttr=d.createAttribute("double");
    doubleAttr.setValue(QString::number(ladspa->usesDoublePlugin()?1:0));
    ladspaDom.setAttributeNode(doubleAttr);

    QDomElement ports=d.createElement("ports");
    ladspaDom.appendChild(ports);



    QPtrList<LADSPAPort>* controlInput=ladspa->getControlInputPorts();
    if(controlInput->count()>0){
        QDomElement controlInputportsDom=d.createElement("control_inputs");
        ports.appendChild(controlInputportsDom);

        QDomAttr portcountAttr=d.createAttribute("count");
        portcountAttr.setValue(QString::number(ladspa->getControlInputPorts()->count()));
        controlInputportsDom.setAttributeNode(portcountAttr);



        for(QPtrList<LADSPAPort>::Iterator it = controlInput->begin(); it != controlInput->end(); ++it){

            QDomElement port=d.createElement("port");
            ports.appendChild(port);

            QDomAttr portnameAttr=d.createAttribute("name");
            portnameAttr.setValue((*it)->getPortName());
            port.setAttributeNode(portnameAttr);

            QDomAttr portidAttr=d.createAttribute("port_no");
            portidAttr.setValue(QString::number((*it)->getPortNumber()));
            port.setAttributeNode(portidAttr);

            EffectPortFrame* portFrame=ef->getPortFrame((*it)->getPortNumber());
            if(portFrame->hasSpline()){
                QDomElement splineDom=d.createElement("spline");
                port.appendChild(splineDom);
                QValueList<SplinePoint> points=portFrame->getSpline()->getSplinePoints();
                for(uint i=0;i<points.count();i++){
                    QDomElement splinepoint=d.createElement("spline-point");
                    splineDom.appendChild(splinepoint);

                    QDomElement point=d.createElement("point");
                    splinepoint.appendChild(point);

                    QDomAttr sampleAttr=d.createAttribute("sample_pos");
                    sampleAttr.setValue(QString::number(points[i].getSamplePos()));
                    point.setAttributeNode(sampleAttr);

                    QDomAttr valueAttr=d.createAttribute("value");
                    valueAttr.setValue(QString::number(points[i].getValue()));
                    point.setAttributeNode(valueAttr);

                    QDomElement cpoint1=d.createElement("control-point-1");
                    splinepoint.appendChild(cpoint1);

                    QDomAttr cp1sampleAttr=d.createAttribute("sample_pos");
                    cp1sampleAttr.setValue(QString::number(points[i].cp1.getSamplePos()));
                    cpoint1.setAttributeNode(cp1sampleAttr);

                    QDomAttr cp1valueAttr=d.createAttribute("value");
                    cp1valueAttr.setValue(QString::number(points[i].cp1.getValue()));
                    cpoint1.setAttributeNode(cp1valueAttr);

                    QDomElement cpoint2=d.createElement("control-point-2");
                    splinepoint.appendChild(cpoint2);

                    QDomAttr cp2sampleAttr=d.createAttribute("sample_pos");
                    cp2sampleAttr.setValue(QString::number(points[i].cp2.getSamplePos()));
                    cpoint2.setAttributeNode(cp2sampleAttr);

                    QDomAttr cp2valueAttr=d.createAttribute("value");
                    cp2valueAttr.setValue(QString::number(points[i].cp2.getValue()));
                    cpoint2.setAttributeNode(cp2valueAttr);
                }
            }
            if(portFrame->hasPolyline()){
                QDomElement polylineDom=d.createElement("polyline");
                port.appendChild(polylineDom);
                QValueList<SortablePoint> points=portFrame->getPolyline()->getSortablePoints();
                for (uint i=0;i<points.count();i++){
                    QDomElement point=d.createElement("point");
                    polylineDom.appendChild(point);

                    QDomAttr sampleAttr=d.createAttribute("sample_pos");
                    sampleAttr.setValue(QString::number(points[i].getSamplePos()));
                    point.setAttributeNode(sampleAttr);

                    QDomAttr valueAttr=d.createAttribute("value");
                    valueAttr.setValue(QString::number(points[i].getValue()));
                    point.setAttributeNode(valueAttr);

                }
            }

            QDomElement valuesDom=d.createElement("values");
            port.appendChild(valuesDom);

            QString valueList;

            QValueList <float> portValues=(*it)->getPortControlValues();
            for (uint j=0;j<portValues.count();j++){
                valueList.append(QString::number(portValues[j]));
                if(j<portValues.count()-1) valueList.append(",");
            }
            QDomText data=d.createTextNode(valueList);
            valuesDom.appendChild(data);

        }
    }

    QPtrList<LADSPAPort>* audiolnput=ladspa->getAudioInputPorts();
    QPtrList<LADSPAPort>* audioOutput=ladspa->getAudioOutputPorts();

    if(audiolnput->count()>0){
        QDomElement audioInputportsDom=d.createElement("audio_inputs");
        ports.appendChild(audioInputportsDom);

        QDomAttr audioinputcountAttr=d.createAttribute("count");
        audioinputcountAttr.setValue(QString::number(audiolnput->count()));
        audioInputportsDom.setAttributeNode(audioinputcountAttr);

        for(QPtrList<LADSPAPort>::Iterator it = audiolnput->begin(); it != audiolnput->end(); ++it){
            QDomElement audioInputDom=d.createElement("audio_input");
            audioInputportsDom.appendChild(audioInputDom);

            QDomAttr portnameAttr=d.createAttribute("name");
            portnameAttr.setValue((*it)->getPortName());
            audioInputDom.setAttributeNode(portnameAttr);

            QDomAttr portidAttr=d.createAttribute("port_no");
            portidAttr.setValue(QString::number((*it)->getPortNumber()));
            audioInputDom.setAttributeNode(portidAttr);

            QDomAttr routingAttr=d.createAttribute("routing");
            routingAttr.setValue(QString::number((*it)->getConnectionMethod()));
            audioInputDom.setAttributeNode(routingAttr);

            if(ladspa->usesDoublePlugin()){
                QDomAttr routingAttr=d.createAttribute("double-routing");
                routingAttr.setValue(QString::number((*it)->getConnectionMethodDouble()));
                audioInputDom.setAttributeNode(routingAttr);
            }
        }

    }

    if(audioOutput->count()>0){
        QDomElement audioOutputportsDom=d.createElement("audio_outputs");
        ports.appendChild(audioOutputportsDom);

        QDomAttr audiooutputcountAttr=d.createAttribute("count");
        audiooutputcountAttr.setValue(QString::number(audioOutput->count()));
        audioOutputportsDom.setAttributeNode(audiooutputcountAttr);

        for(QPtrList<LADSPAPort>::Iterator it = audioOutput->begin(); it != audioOutput->end(); ++it){
            QDomElement audioOutputDom=d.createElement("audio_output");
            audioOutputportsDom.appendChild(audioOutputDom);

            QDomAttr portnameAttr=d.createAttribute("name");
            portnameAttr.setValue((*it)->getPortName());
            audioOutputDom.setAttributeNode(portnameAttr);

            QDomAttr portidAttr=d.createAttribute("port_no");
            portidAttr.setValue(QString::number((*it)->getPortNumber()));
            audioOutputDom.setAttributeNode(portidAttr);

            QDomAttr routingAttr=d.createAttribute("routing");
            routingAttr.setValue(QString::number((*it)->getConnectionMethod()));
            audioOutputDom.setAttributeNode(routingAttr);

            if(ladspa->usesDoublePlugin()){
                QDomAttr routingAttr=d.createAttribute("double-routing");
                routingAttr.setValue(QString::number((*it)->getConnectionMethodDouble()));
                audioOutputDom.setAttributeNode(routingAttr);
            }
        }
    }

    return d;
}


/*!
    \fn ProjectManager::setLadspa(EffectFrame* ef)
 */
void ProjectManager::setLadspa(EffectFrame* ef)
{
    effectFrame=ef;
}


/*!
    \fn ProjectManager::loadProject(QString filename)
 */
void ProjectManager::loadProject(QString fn)
{

    setFilename(fn);
    clearPolylinesSplines();

    cout<<"Filename: "<<filename<<"\n";    
    QFile file(filename);
    QFileInfo finfo(filename);


    QProcess proc(this);
    proc.addArgument("tar");
    proc.addArgument("xz");
    proc.addArgument("-C");
    proc.addArgument(soundManager->getTempDir());
    proc.addArgument("-f");
    proc.addArgument(filename);
    cout<<"Executing "<<proc.arguments().join(" ")<<"\n";
    proc.start();
    while(proc.isRunning()) sleep(10);

    QDir uncompressedDir(soundManager->getTempDir()+"/"+finfo.baseName());


    if(!uncompressedDir.exists()){
        cout<<"hum, it seems that the file was renamed..my fault..didn't think of that.\n";
        cout<<"trying to list the archive...\n";
        QProcess proc2(this);
        proc2.addArgument("tar");
        proc2.addArgument("tz");
        proc2.addArgument("-C");
        proc2.addArgument(soundManager->getTempDir());
        proc2.addArgument("-f");
        proc2.addArgument(filename);
        proc2.start();
        while(proc2.isRunning()) sleep(10);
        QString dirname=proc2.readLineStdout();
        uncompressedDir.setPath(soundManager->getTempDir()+"/"+dirname);
    }

    QStringList filelist=uncompressedDir.entryList();
    QString wavefile(uncompressedDir.path()+"/"+filelist.grep("orig-wave.").front());
    QString projectfile(uncompressedDir.path()+"/"+filelist.grep(".xml").front());

    cout<<"loading wave: "<<wavefile<<"\n";
    emit(loadFile((const QString)(wavefile)));
    cout<<"loading project: "<<projectfile<<"\n";

    QDomDocument doc;
    QFile projectFile(projectfile );
    if ( !projectFile.open( IO_ReadOnly ) )
        return;
    if ( !doc.setContent( &projectFile ) ) {
        projectFile.close();
        return;
    }
    projectFile.close();
    if(doc.elementsByTagName("beatlines").count()!=0){
        xmlToLBL(doc.elementsByTagName("beatlines").item(0));
    }
     if(doc.elementsByTagName("envelope").count()!=0){
        xmlToEnvelope(doc.elementsByTagName("envelope").item(0),envelopeData);
        emit(envelopeDataChanged());
    }
    if(doc.elementsByTagName("ladspa").count()!=0){
        xmlToLADSPA(doc.elementsByTagName("ladspa").item(0));
    }
    if(doc.elementsByTagName("loop").count()!=0){
        xmlToLoopMarkers(doc.elementsByTagName("loop").item(0),leftLoopMarker,rightLoopMarker);
    }
    if(doc.elementsByTagName("stacks").count()!=0){
        xmlToStacks(doc.elementsByTagName("stacks").item(0));
    }
    if(!doc.elementsByTagName("freecycle").item(0).attributes().namedItem("bpm-modifier").isNull()){
        QString bpmModifier=
    doc.elementsByTagName("freecycle").item(0).attributes().namedItem("bpm-modifier").toAttr().value();
        emit(bpmModifierChangeS(bpmModifier));
    }
    
    FileManager::deleteDir(uncompressedDir.path());
}


/*!
    \fn ProjectManager::xmlToEnvelope(QDomNode xml, EnvelopeData* envData)
 */
void ProjectManager::xmlToEnvelope(QDomNode xml, EnvelopeData* envData)
{
    envData->attack=xml.attributes().namedItem("attack").toAttr().value().toFloat();
    envData->attackC.setX(xml.attributes().namedItem("attackCx").toAttr().value().toFloat());
    envData->attackC.setY(xml.attributes().namedItem("attackCy").toAttr().value().toFloat());
    envData->hold=xml.attributes().namedItem("hold").toAttr().value().toFloat();
    envData->decay=xml.attributes().namedItem("decay").toAttr().value().toFloat();
    envData->decayC.setX(xml.attributes().namedItem("decayCx").toAttr().value().toFloat());
    envData->decayC.setY(xml.attributes().namedItem("decayCy").toAttr().value().toFloat());
    envData->sustain=xml.attributes().namedItem("sustain").toAttr().value().toFloat();
    envData->release=xml.attributes().namedItem("release").toAttr().value().toFloat();
    envData->releaseC.setX(xml.attributes().namedItem("releaseCx").toAttr().value().toFloat());
    envData->releaseC.setY(xml.attributes().namedItem("releaseCy").toAttr().value().toFloat());
    envData->env_duration=xml.attributes().namedItem("duration").toAttr().value().toFloat();
    envData->env_resolution=xml.attributes().namedItem("resolution").toAttr().value().toFloat();
    envData->env_mode=(EnvelopeData::mode)(xml.attributes().namedItem("mode").toAttr().value().toInt());
    envData->setEnabled(xml.attributes().namedItem("active").toAttr().value().toInt());

}




/*!
    \fn ProjectManager::xmlToLADSPA(QDomNode xml)
 */
void ProjectManager::xmlToLADSPA(QDomNode xml)
{
    if(!xml.isNull()){
        int uid=xml.attributes().namedItem("uid").toAttr().value().toInt();
        LADSPAEffect* ladspa=soundManager->getEffects()->getEffect(uid);
        if(!ladspa){
            QString warning="Cannot find LADSPA: "+xml.attributes().namedItem("name").toAttr().value();
            cout<<warning<<"\n";
            QMessageBox::warning(0,"LADSPA problem",warning);
            return;
        }
        int double_=xml.attributes().namedItem("double").toAttr().value().toInt();
        ladspa->setInUse(1);
        ladspa->setDoublePlugin(double_);


        //assign autio routings
        QDomNodeList audioInputs=xml.toElement().elementsByTagName("audio_input");
        if(audioInputs.count()>0){
            for (uint i=0;i<audioInputs.count();i++){
                int port_no=audioInputs.item(i).attributes().namedItem("port_no").toAttr().value().toInt();
                int routing=audioInputs.item(i).attributes().namedItem("routing").toAttr().value().toInt();
                LADSPAPort* port=ladspa->getPort(port_no);
                port->setConnectionMethod((LADSPAPort::ConnectionMethod)routing);
                if(double_){
                    int double_routing=
                            audioInputs.item(i).attributes().namedItem("double-routing").toAttr().value().toInt();
                    port->setConnectionMethodDouble((LADSPAPort::ConnectionMethod)double_routing);
                }
            }
        }
        QDomNodeList audioOutputs=xml.toElement().elementsByTagName("audio_output");
        if(audioOutputs.count()>0){
            for (uint i=0;i<audioOutputs.count();i++){
                int port_no=audioOutputs.item(i).attributes().namedItem("port_no").toAttr().value().toInt();
                int routing=audioOutputs.item(i).attributes().namedItem("routing").toAttr().value().toInt();
                LADSPAPort* port=ladspa->getPort(port_no);
                port->setConnectionMethod((LADSPAPort::ConnectionMethod)routing);
                if(double_){
                    int double_routing=
                            audioOutputs.item(i).attributes().namedItem("double-routing").toAttr().value().toInt();
                    port->setConnectionMethodDouble((LADSPAPort::ConnectionMethod)double_routing);
                }
            }
        }
        //end assign autio routings

        //assign control inputs values
        QDomNodeList controlInputs=xml.toElement().elementsByTagName("port");
        cout<<"controlInputs: "<<controlInputs.count()<<"\n";
        int ok=TRUE;
        if(controlInputs.count()>0){
            for (uint i=0;i<controlInputs.count();i++){
                int port_no=controlInputs.item(i).attributes().namedItem("port_no").toAttr().value().toInt();
                QString value=
                  controlInputs.item(i).toElement().elementsByTagName("values").item(0).firstChild().toText().data();
                QStringList values=QStringList::split(",",value);
                QValueList<float> fvalues;
                LADSPAPort* port=ladspa->getPort(port_no);
                for (uint j=0;j<values.count();j++){
                    fvalues.append(values[j].toFloat());
                }
                if(fvalues.count()!=0){
                    port->initControlValues(fvalues);
                }else ok=FALSE;

                //create polylines (if any)
                QDomNodeList polylinesNL=controlInputs.item(i).toElement().elementsByTagName("polyline");
                if (polylinesNL.count()>0){
                    QValueList <SortablePoint> polypoints=xmlToPolylineData(polylinesNL.item(0));
                    polylinesMap.insert(port_no,polypoints);
                }
                //end create polylines (if any)
                //create splines (if any)
                QDomNodeList splinesNL=controlInputs.item(i).toElement().elementsByTagName("spline");
                if (splinesNL.count()>0){
                    QValueList <SplinePoint> splinepoints=xmlToSplineData(splinesNL.item(0));
                    splinesMap.insert(port_no,splinepoints);
                }
                //end create splines (if any)
            }
        }
        if(ok) ladspa->setPortInitDone(TRUE);
        //assign control inputs values



        emit(addLadspa(uid));
    }
}


/*!
    \fn ProjectManager::xmlToLBL(QDomNode xml)
 */
void ProjectManager::xmlToLBL(QDomNode xml)
{
    if(!xml.isNull()){
        QValueList <beatline_data> positions;
        QDomNodeList beatlines=xml.childNodes();
        for (uint i=0;i<beatlines.count();i++){
            QDomNode beatline=beatlines.item(i);
            beatline_data bld;
            bld.position=beatline.attributes().namedItem("position").toAttr().value().toLong();
            bld.midiNote=beatline.attributes().namedItem("midiNote").isNull()?-1:
                            beatline.attributes().namedItem("midiNote").toAttr().value().toInt();
            bld.locked=1;
            positions.append(bld);
        }
        emit(addLockedBeatlines(positions));
    }
}


/*!
    \fn ProjectManager::xmlToPolylineData(QDomNode xml)
 */
QValueList <SortablePoint> ProjectManager::xmlToPolylineData(QDomNode xml)
{
    QValueList <SortablePoint> polypoints;
    QDomNodeList polypointsNL=xml.toElement().elementsByTagName("point");
    for (uint i=0;i<polypointsNL.count();i++){
        long sample_pos=polypointsNL.item(i).attributes().namedItem("sample_pos").toAttr().value().toLong();
        float value=polypointsNL.item(i).attributes().namedItem("value").toAttr().value().toFloat();
        SortablePoint point;
        point.setSamplePos(sample_pos);
        point.setValue(value);
        polypoints.append(point);
    }
    return polypoints;
}


/*!
    \fn ProjectManager::xmlToSplineData(QDomNode xml)
 */
QValueList<SplinePoint> ProjectManager::xmlToSplineData(QDomNode xml)
{
    QValueList <SplinePoint> splinepoints;
    QDomNodeList splinepointsNL=xml.toElement().elementsByTagName("spline-point");
    for (uint i=0;i<splinepointsNL.count();i++){
        QDomNode pointDN=splinepointsNL.item(i).toElement().elementsByTagName("point").item(0);
        long sample_pos_p=pointDN.attributes().namedItem("sample_pos").toAttr().value().toLong();
        float value_p=pointDN.attributes().namedItem("value").toAttr().value().toFloat();
        SplinePoint point;
        point.setSamplePos(sample_pos_p);
        point.setValue(value_p);

        QDomNode cpoint1DN=
                splinepointsNL.item(i).toElement().elementsByTagName("control-point-1").item(0);
        long sample_pos_cp1=cpoint1DN.attributes().namedItem("sample_pos").toAttr().value().toLong();
        float value_cp1=cpoint1DN.attributes().namedItem("value").toAttr().value().toFloat();
        point.cp1.setSamplePos(sample_pos_cp1);
        point.cp1.setValue(value_cp1);

        QDomNode cpoint2DN=
                splinepointsNL.item(i).toElement().elementsByTagName("control-point-2").item(0);
        long sample_pos_cp2=cpoint2DN.attributes().namedItem("sample_pos").toAttr().value().toLong();
        float value_cp2=cpoint2DN.attributes().namedItem("value").toAttr().value().toFloat();
        point.cp2.setSamplePos(sample_pos_cp2);
        point.cp2.setValue(value_cp2);

        splinepoints.append(point);
    }

    return splinepoints;
}



/*!
    \fn ProjectManager::getPolylines()
 */
ProjectManager::polylinesMapT ProjectManager::getPolylines()
{
    return polylinesMap;
}


/*!
    \fn ProjectManager::getSplines()
 */
ProjectManager::splinesMapT ProjectManager::getSplines()
{
    return splinesMap;
}


/*!
    \fn ProjectManager::clearPolylinesSplines()
 */
void ProjectManager::clearPolylinesSplines()
{
    polylinesMap.clear();
    splinesMap.clear();
}


/*!
    \fn ProjectManager::setLoopMarkers(LoopMarker* l, LoopMarker* r)
 */
void ProjectManager::setLoopMarkers(LoopMarker* l, LoopMarker* r)
{
    leftLoopMarker=l;
    rightLoopMarker=r;
}


/*!
    \fn ProjectManager::loopMarkersToXML(LoopMarker* l, LoopMarker* r)
 */
QDomNode ProjectManager::loopMarkersToXML(LoopMarker* l, LoopMarker* r)
{
    QDomDocument d;
    if(l && r){
        QDomElement loopDom=d.createElement("loop");
        d.appendChild(loopDom);

        QDomAttr leftAttr=d.createAttribute("left");
        leftAttr.setValue(QString::number(l->getSamplePosition()));
        loopDom.setAttributeNode(leftAttr);

        QDomAttr rightAttr=d.createAttribute("right");
        rightAttr.setValue(QString::number(r->getSamplePosition()));
        loopDom.setAttributeNode(rightAttr);
    }
    return d;
}


/*!
    \fn ProjectManager::xmlToLoopMarkers(QDomNode xml, LoopMarker* l, LoopMarker* r)
 */
void ProjectManager::xmlToLoopMarkers(QDomNode xml, LoopMarker* l, LoopMarker* r)
{
    long left_pos=xml.attributes().namedItem("left").toAttr().value().toLong();
    long right_pos=xml.attributes().namedItem("right").toAttr().value().toLong();
    l->setSamplePosition(left_pos);
    r->setSamplePosition(right_pos);
}


/*!
    \fn ProjectManager::getFilename()
 */
QString ProjectManager::getFilename()
{
    return filename;
}


/*!
    \fn ProjectManager::stacksToXML()
 */
QDomNode ProjectManager::stacksToXML(LockedBeatRectList lbrl)
{
    QPtrListIterator<LockedBeatRect> it( lbrl );
    LockedBeatRect *beatrect;
    QDomDocument d;
    QDomElement stacksDom=d.createElement("stacks");
    d.appendChild(stacksDom);
    while ( (beatrect = it.current()) != 0 ) {
        ++it;
        if(beatrect->getSampleNumberDisplays().count()>0){
            stacksDom.appendChild(stackToXML(beatrect->getSampleNumberDisplays(),
                    beatrect->getStartSample(),beatrect->getEndSample()));
        }
        
    }
    return d;
}


/*!
    \fn ProjectManager::setLockedBeatRects(LockedBeatRectList lbrl)
 */
void ProjectManager::setLockedBeatRects(LockedBeatRectList lbrl)
{
    lockedBeatRects=lbrl;
}


/*!
    \fn ProjectManager::stackToXML(QPtrList <SampleNumberDisplay> snds, long start, long end)
 */
QDomNode ProjectManager::stackToXML(QPtrList <SampleNumberDisplay> snds, long start, long end)
{
    QDomDocument d;
    QDomElement stackDom=d.createElement("stack");
    d.appendChild(stackDom);
    
    QDomAttr leftAttr=d.createAttribute("left");
    leftAttr.setValue(QString::number(start));
    stackDom.setAttributeNode(leftAttr);
    
    QDomAttr rightAttr=d.createAttribute("right");
    rightAttr.setValue(QString::number(end));
    stackDom.setAttributeNode(rightAttr);
    
    QPtrListIterator<SampleNumberDisplay> it( snds );
    SampleNumberDisplay *snd;
    while ( (snd = it.current()) != 0 ) {
        ++it;
        QDomElement stackElementDom=d.createElement("stackElement");
        stackDom.appendChild(stackElementDom);
        
        QDomAttr filenameAttr=d.createAttribute("filename");
        filenameAttr.setValue(QFileInfo(snd->getAssignedFile()).fileName());
        stackElementDom.setAttributeNode(filenameAttr);
        
        QDomAttr indexAttr=d.createAttribute("index");
        indexAttr.setValue(QString::number(snd->getNumber()));
        stackElementDom.setAttributeNode(indexAttr);
        
        QDomAttr sceneAttr=d.createAttribute("scene");
        sceneAttr.setValue(QString::number(snd->getScene()));
        stackElementDom.setAttributeNode(sceneAttr);
        
        if(snd->getCurrent()){
            QDomAttr currentAttr=d.createAttribute("current");
            currentAttr.setValue("1");
            stackElementDom.setAttributeNode(currentAttr);
        }
    }
    
    return d;
}


/*!
    \fn ProjectManager::saveStackElementWaves(QString dir, LockedBeatRectList lbrl)
 */
void ProjectManager::saveStackElementWaves(QString dir, LockedBeatRectList lbrl)
{
    QPtrListIterator<LockedBeatRect> it( lbrl );
    LockedBeatRect *beatrect;
    QStringList files;
    while ( (beatrect = it.current()) != 0 ) {
        ++it;
        QPtrList <SampleNumberDisplay> snds=beatrect->getSampleNumberDisplays();
        if(snds.count()>0){
            QPtrListIterator<SampleNumberDisplay> it2( snds );
            SampleNumberDisplay *snd;
            while ( (snd = it2.current()) != 0 ) {
                ++it2;
                files.append(""+snd->getAssignedFile());
            }
        }
    }
    if(files.count()>0){
        copyFilesToDir(files,dir);
    }
}


/*!
    \fn ProjectManager::copyFilesToDir(QStringList files, QString dir)
 */
int ProjectManager::copyFilesToDir(QStringList files, QString dir)
{
    for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it ) {
        copyFileToDir(*it,dir);
    }
    return 0;
}


/*!
    \fn ProjectManager::copyFileToDir(QString file, QString dir)
 */
int ProjectManager::copyFileToDir(QString inputfile, QString dir)
{
    
     QFile input(inputfile);
     if(!input.open(IO_ReadOnly)){
         cout<<"cannot read "<<inputfile<<"\n";
         return 1;
     }
     QFile output(dir+"/"+QFileInfo(inputfile).fileName());
     if(!output.open(IO_WriteOnly)){
         cout<<"cannot write "<<output.name()<<"\n";
         return 1;
     }
     output.writeBlock(input.readAll());
     output.close();
     input.close();
     return 0;
}


/*!
    \fn ProjectManager::xmlToStacks(QDomNode xml)
 */
void ProjectManager::xmlToStacks(QDomNode xml)
{
    if(!xml.isNull()){
        QDomNodeList stacks=xml.childNodes();
        for (uint i=0;i<stacks.count();i++){
            QDomNode stack=stacks.item(i);
            xmlToStack(stack);
        }
    }
}

/*!
    \fn ProjectManager::xmlToStack(QDomNode xml)
 */
void ProjectManager::xmlToStack(QDomNode xml)
{
   if(!xml.isNull()){
        long left_pos=xml.attributes().namedItem("left").toAttr().value().toLong();
        long right_pos=xml.attributes().namedItem("right").toAttr().value().toLong();
        QDomNodeList stackElements=xml.childNodes();
        for (uint i=0;i<stackElements.count();i++){
            QDomNode stackElement=stackElements.item(i);
            xmlToStackElement(stackElement,left_pos,right_pos);
        }
    }
}





/*!
    \fn ProjectManager::xmlToStackElement(QDomNode xml, long left, long right)
 */
void ProjectManager::xmlToStackElement(QDomNode xml, long left, long right)
{
    QFileInfo finfo(filename);
    QString uncompressedDir=soundManager->getTempDir()+"/"+finfo.baseName();
    
    int index=xml.attributes().namedItem("index").toAttr().value().toInt();
    int scene=xml.attributes().namedItem("scene").toAttr().value().toInt();
    QString stackElemFilename=xml.attributes().namedItem("filename").toAttr().value();
    bool current=xml.attributes().namedItem("current").isNull()?FALSE:
                    xml.attributes().namedItem("current").toAttr().value().toInt();
    
    copyFileToDir(uncompressedDir+"/"+stackElemFilename,soundManager->getTempDir());
    cout<<"copying "<<uncompressedDir+"/"+stackElemFilename<<" to "<<soundManager->getTempDir()<<"\n";
    emit(addStackElementS(left,right,
            soundManager->getTempDir()+"/"+stackElemFilename,index,scene,current));
}


void ProjectManager::setBpmModifier(const QString& theValue) {
    bpmModifier = theValue;
}
