//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: conf.cpp,v 1.1.1.1 2003/10/29 10:05:08 wschweer Exp $
//
//  (C) Copyright 1999/2000 Werner Schweer (ws@seh.de)
//=========================================================

#include "app.h"
#include <qlistview.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qcombobox.h>
#include <qlabel.h>
#include <qbuttongroup.h>
#include <stdio.h>
#include <qpopupmenu.h>
#include <qgroupbox.h>
#include <qradiobutton.h>
#include <qspinbox.h>
#include <qcheckbox.h>
#include <qsignalmapper.h>
#include <qtooltip.h>

#include "icons.h"
#include "globals.h"
#include "drumedit.h"
#include "pianoroll.h"
#include "master/masteredit.h"
#include "score/score.h"
#include "transport.h"
#include "bigtime.h"
#include "arranger.h"
#include "seq.h"
#include "conf.h"
#include "pitchedit.h"
#include "midiport.h"
#include "driver/mididev.h"
#include "driver/midiserial.h"
#include "driver/audiodev.h"
#include "xml.h"
#include "waveedit.h"
#include "midisyncimpl.h"
#include "midifilterimpl.h"
#include "ctrlcombo.h"
#include "genset.h"
#include "midiitransform.h"
#include "synth.h"
#include "audioconf.h"
#include "audio.h"
#include "sync.h"

#include <errno.h>

extern void writeMidiTransforms(int level, Xml& xml);
extern void readMidiTransform(Xml&);

extern void writeMidiInputTransforms(int level, Xml& xml);
extern void readMidiInputTransform(Xml&);

QString printerFile;
QString printerCommand;
bool printerType;        // 1 file, 0 command
QString previewCommand;

//---------------------------------------------------------
//   readGeometry
//---------------------------------------------------------

QRect readGeometry(Xml& xml)
      {
      QRect r(0, 0, 50, 50);
      int val;

      for (;;) {
            Xml::Token token = xml.parse();
            if (token == Xml::Error || token == Xml::End)
                  break;
            QString tag = xml.s1();
            switch (token) {
                  case Xml::TagStart:
                        xml.parse1();
                        break;
                  case Xml::Attribut:
                        val = xml.s2().toInt();
                        if (tag == "x")
                              r.setX(val);
                        else if (tag == "y")
                              r.setY(val);
                        else if (tag == "w")
                              r.setWidth(val);
                        else if (tag == "h")
                              r.setHeight(val);
                        break;
                  case Xml::TagEnd:
                        if (tag == "geometry")
                              return r;
                  default:
                        break;
                  }
            }
      return r;
      }


//---------------------------------------------------------
//   readColor
//---------------------------------------------------------

QColor readColor(Xml& xml)
       {
       int val, r=0, g=0, b=0;

      for (;;) {
            Xml::Token token = xml.parse();
            if (token != Xml::Attribut)
                  break;
            QString tag = xml.s1();
            switch (token) {
                  case Xml::Attribut:
                        val = xml.s2().toInt();
                        if (tag == "r")
                              r = val;
                        else if (tag == "g")
                              g = val;
                        else if (tag == "b")
                              b = val;
                        break;
                  default:
                        break;
                  }
            }

      return QColor(r, g, b);
      }

//---------------------------------------------------------
//   readConfigTransport
//---------------------------------------------------------

void MusE::readConfigTransport(Xml& xml)
      {
      QString a;
      int val;

      for (;;) {
            Xml::Token token = xml.parse();
            if (token == Xml::Error || token == Xml::End)
                  break;
            QString tag = xml.s1();
            switch (token) {
                  case Xml::TagStart:
                        if (tag == "geometry") {
                              configGeometryTransport = readGeometry(xml);
                              // use only position
                              configGeometryTransport.setWidth(0);
                              configGeometryTransport.setHeight(0);
                              }
                        else if (tag == "handlecolor")
                              configTransportHandleColor = readColor(xml);
                        else
                              xml.unknown("Transport");
                        break;
                  case Xml::Attribut:
                        val = xml.s2().toInt();
                        if (tag == "visible")
                              configTransportVisible = val;
                        break;
                  case Xml::TagEnd:
                        if (tag == "transport")
                              return;
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   readConfigBigTime
//---------------------------------------------------------

void MusE::readConfigBigTime(Xml& xml)
      {
      QString a;
      int val;

      for (;;) {
            Xml::Token token = xml.parse();
            if (token == Xml::Error || token == Xml::End)
                  break;
            QString tag = xml.s1();
            switch (token) {
                  case Xml::TagStart:
                        if (tag == "geometry")
                              configGeometryBigTime = readGeometry(xml);
                        else if (tag == "foregroundcolor")
                              configBigTimeForegroundColor = readColor(xml);
                        else if (tag == "backgroundcolor")
                              configBigTimeBackgroundColor = readColor(xml);
                        else
                              xml.unknown("BigTime");
                        break;
                  case Xml::Attribut:
                        val = xml.s2().toInt();
                        if (tag == "visible")
                              configBigTimeVisible = val;
                        break;
                  case Xml::TagEnd:
                        if (tag == "bigtime")
                              return;
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   readConfigPrinter
//---------------------------------------------------------

void MusE::readConfigPrinter(Xml& xml)
      {
      for (;;) {
            Xml::Token token = xml.parse();
            QString tag = xml.s1();
            if (token == Xml::Error || token == Xml::End)
                  break;
// printf("printer <%s>\n", tag.latin1());
            switch (token) {
                  case Xml::TagStart:
                        if (tag == "cmd")
                              printerCommand = xml.parse1();
                        else if (tag == "file")
                              printerFile = xml.parse1();
                        else if (tag == "preview")
                              previewCommand = xml.parse1();
                        else
                              xml.unknown("Printer");
                        break;
                  case Xml::Attribut:
                        if (tag == "type")
                              printerType = xml.s2().toInt();
                        break;
                  case Xml::TagEnd:
                        if (tag == "printer")
                              return;
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   readConfiguration
//---------------------------------------------------------

bool MusE::readConfiguration()
      {
      FILE* f = fopen(configName.latin1(), "r");
      if (f == 0) {
            printf("NO Config File <%s>\n", configName.latin1());
            return true;
            }
      Xml xml(f);
      read(xml);
      fclose(f);
      return false;
      }

void MusE::readConfiguration(Xml& xml)
      {
      int version;
      extern bool configLoaded;
      configLoaded = true;
      for (;;) {
            Xml::Token token = xml.parse();
            if (token == Xml::Error || token == Xml::End)
                  break;
            QString tag = xml.s1();
            switch (token) {
                  case Xml::TagStart:
                        if (tag == "geometry")
                              configGeometryMain = readGeometry(xml);
                        else if (tag == "theme")
                              configTheme = xml.parse1();
                        else if (tag == "fontSize")  // obsolete
                              ;
                        else if (tag == "font0")
                              font0.fromString(xml.parse1());
                        else if (tag == "font1")
                              font1.fromString(xml.parse1());
                        else if (tag == "font2")
                              font2.fromString(xml.parse1());
                        else if (tag == "font3")
                              font3.fromString(xml.parse1());
                        else if (tag == "font4")
                              font4.fromString(xml.parse1());
                        else if (tag == "font5")
                              font5.fromString(xml.parse1());
                        else if (tag == "activityMode")
                              configActivityMode = xml.parseInt();
                        else if (tag == "activityColor")
                              configActivityColor = readColor(xml);
                        else if (tag == "selectedTrackColor")
                              /*configSelectedTrackColor =*/ readColor(xml);
                        else if (tag == "extendedMidi")
                              extendedMidi = xml.parseInt();
                        else if (tag == "midiExportDivision")
                              midiDivision = xml.parseInt();
                        else if (tag == "midiInputDevice")
                              midiInputPorts = xml.parseInt();
                        else if (tag == "midiInputChannel")
                              midiInputChannel = xml.parseInt();
                        else if (tag == "midiRecordType")
                              midiRecordType = xml.parseInt();
                        else if (tag == "midiThruType")
                              midiThruType = xml.parseInt();
                        else if (tag == "midiFilterCtrl1")
                              midiFilterCtrl1 = xml.parseInt();
                        else if (tag == "midiFilterCtrl2")
                              midiFilterCtrl2 = xml.parseInt();
                        else if (tag == "midiFilterCtrl3")
                              midiFilterCtrl3 = xml.parseInt();
                        else if (tag == "midiFilterCtrl4")
                              midiFilterCtrl4 = xml.parseInt();
                        else if (tag == "transport")
                              readConfigTransport(xml);
                        else if (tag == "bigtime")
                              readConfigBigTime(xml);
                        else if (tag == "deviceid")    // obsolete
                              xml.parseInt();
                        else if (tag == "txDeviceId")
                              txDeviceId = xml.parseInt();
                        else if (tag == "rxDeviceId")
                              rxDeviceId = xml.parseInt();
                        else if (tag == "syncport")   // obsolete
                              xml.parseInt();
                        else if (tag == "txSyncPort")
                              txSyncPort= xml.parseInt();
                        else if (tag == "rxSyncPort")
                              rxSyncPort= xml.parseInt();
                        else if (tag == "mtctype")
                              mtcType= xml.parseInt();
                        else if (tag == "extSync")
                              extSyncFlag.setValue(xml.parseInt());
                        else if (tag == "syncgentype") {
                              // for compatibility
                              int syncGenType= xml.parseInt();
                              genMTCSync = syncGenType == 1;
                              genMCSync = syncGenType == 2;
                              }
                        else if (tag == "genMTCSync")
                              genMTCSync = xml.parseInt();
                        else if (tag == "genMCSync")
                              genMCSync = xml.parseInt();
                        else if (tag == "genMMC")
                              genMMC = xml.parseInt();
                        else if (tag == "acceptMTC")
                              acceptMTC = xml.parseInt();
                        else if (tag == "acceptMMC")
                              acceptMMC = xml.parseInt();
                        else if (tag == "acceptMC")
                              acceptMC = xml.parseInt();
                        else if (tag == "mtcoffset") {
                              QString qs(xml.parse1());
                              const char* str = qs.latin1();
                              int h, m, s, f, sf;
                              sscanf(str, "%d:%d:%d:%d:%d", &h, &m, &s, &f, &sf);
                              mtcOffset = MTC(h, m, s, f, sf);
                              }
                        else if (tag == "score")
                              Score::readConfiguration(xml);
                        else if (tag == "printer")
                              readConfigPrinter(xml);
                        else if (tag == "sequencer")
                              seq->readConfiguration(xml);
                        else if (tag == "arranger")
                              arranger->readStatus(xml);
                        else if (tag == "drumedit")
                              DrumEdit::readConfiguration(xml);
                        else if (tag == "pianoroll")
                              PianoRoll::readConfiguration(xml);
                        else if (tag == "masteredit")
                              MasterEdit::readConfiguration(xml);
                        else if (tag == "score")
                              Score::readConfiguration(xml);
                        else if (tag == "waveedit")
                              WaveEdit::readConfiguration(xml);
                        else if (tag == "division")
                              division = xml.parseInt();
                        else if (tag == "samplerate")
                              sampleRate = xml.parseInt();
                        else if (tag == "useAlsa") {
                              useAlsaAudio = xml.parseInt();
                              useJackAudio = !useAlsaAudio;
                              }
                        else if (tag == "useJack") {
                              useJackAudio = xml.parseInt();
                              useAlsaAudio = ! useJackAudio;
                              }
                        else if (tag == "segmentsize")
                              segmentSize = xml.parseInt();
                        else if (tag == "rtcTicks")
                              rtcTicks = xml.parseInt();
                        else if (tag == "minMeter")
                              minMeter = xml.parseInt();
                        else if (tag == "minSlider")
                              minSlider = xml.parseDouble();
                        else if (tag == "guiRefresh")
                              guiRefresh = xml.parseInt();
                        else if (tag == "helpBrowser")
                              helpBrowser = xml.parse1();
                        else if (tag == "audioInput") {
                              QString s = xml.parse1();
                              if (audioDevice)
                                    audioDevice->setInputPort(s);
                              }
                        else if (tag == "audioOutput") {
                              QString s = xml.parse1();
                              if (audioDevice)
                                    audioDevice->setOutputPort(s);
                              }
                        else if (tag == "serialPort")
                              readSerialPort(xml);
                        else if (tag == "midiTransform")
                              readMidiTransform(xml);
                        else if (tag == "midiInputTransform")
                              readMidiInputTransform(xml);
                        else if (tag == "synth")
                              readSoftSynth(xml);
                        else
                              xml.unknown("configuration");
                        break;
                  case Xml::Text:
                        printf("text <%s>\n", xml.s1().latin1());
                        break;
                  case Xml::Attribut:
                        if (tag == "version")
                              version= xml.s2().toInt();
                        break;
                  case Xml::TagEnd:
                        if (tag == "configuration") {
                              return;
                              }
                        break;
                  case Xml::Proc:
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   writeConfiguration
//---------------------------------------------------------

void MusE::writeConfiguration() const
      {
      FILE* f = fopen(configName.latin1(), "w");
      if (f == 0) {
            printf("save configuration to <%s> failed: %s\n",
               configName.latin1(), strerror(errno));
            return;
            }
      Xml xml(f);
      xml.header();
      xml.tag(0, "muse version=\"1.0\"");
      writeConfiguration(1, xml);
      xml.tag(1, "/muse");
      fclose(f);
      }

void MusE::writeConfiguration(int level, Xml& xml) const
      {
      xml.tag(level++, "configuration");
      xml.tag(level++, "geometry x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"",
            frameGeometry().x(),
            frameGeometry().y(),
            geometry().width(),
            geometry().height());
      xml.tag(level--, "/geometry");

      if (division != 384)
            xml.intTag(level, "division", division);
      if (sampleRate != 44100)
            xml.intTag(level, "samplerate", sampleRate);
      if (segmentSize != 4096)
            xml.intTag(level, "segmentsize", segmentSize);
      if (rtcTicks != 4096)
            xml.intTag(level, "rtcTicks", rtcTicks);
      if (useAlsaAudio)
            xml.intTag(level, "useAlsa", useAlsaAudio);
      if (useJackAudio)
            xml.intTag(level, "useJack", useJackAudio);
      if (minMeter != -60)
            xml.intTag(level, "minMeter", minMeter);
      if (minSlider != -60.0)
            xml.doubleTag(level, "minSlider", minSlider);
      if (guiRefresh != 20)
            xml.intTag(level, "guiRefresh", guiRefresh);
      if (helpBrowser != QString("konqueror"))
            xml.strTag(level, "helpBrowser", helpBrowser);
      if (audioDevice) {
            xml.strTag(level, "audioInput", audioDevice->inputPort());
            xml.strTag(level, "audioOutput", audioDevice->outputPort());
            }
      xml.intTag(level, "extendedMidi", extendedMidi);
      xml.intTag(level, "midiExportDivision", midiDivision);
      xml.intTag(level, "midiInputDevice", midiInputPorts);
      xml.intTag(level, "midiInputChannel", midiInputChannel);
      xml.intTag(level, "midiRecordType", midiRecordType);
      xml.intTag(level, "midiThruType", midiThruType);
      xml.intTag(level, "midiFilterCtrl1", midiFilterCtrl1);
      xml.intTag(level, "midiFilterCtrl2", midiFilterCtrl2);
      xml.intTag(level, "midiFilterCtrl3", midiFilterCtrl3);
      xml.intTag(level, "midiFilterCtrl4", midiFilterCtrl4);
      xml.intTag(level, "txDeviceId", txDeviceId);
      xml.intTag(level, "rxDeviceId", rxDeviceId);
      xml.nput(level, "<theme>%s</theme>\n", _currentTheme.ascii());

      xml.strTag(level, "font0", font0.toString());
      xml.strTag(level, "font1", font1.toString());
      xml.strTag(level, "font2", font2.toString());
      xml.strTag(level, "font3", font3.toString());
      xml.strTag(level, "font4", font4.toString());
      xml.strTag(level, "font5", font5.toString());

      xml.nput(level, "<activityColor r=\"%d\" g=\"%d\" b=\"%d\"></activityColor>\n",
      		arranger->getActivityColor().red(),
      		arranger->getActivityColor().green(),
      		arranger->getActivityColor().blue());
/*      xml.nput(level, "<selectedTrackColor r=\"%d\" g=\"%d\" b=\"%d\"></selectedTrackColor>\n",
      		arranger->getSelectedTrackColor().red(),
      		arranger->getSelectedTrackColor().green(),
      		arranger->getSelectedTrackColor().blue());
 */
      xml.intTag(level, "activityMode", arranger->getActivityMode());

      xml.intTag(level, "txSyncPort", txSyncPort);
      xml.intTag(level, "rxSyncPort", rxSyncPort);
      xml.intTag(level, "mtctype", mtcType);
      xml.nput(level, "<mtcoffset>%02d:%02d:%02d:%02d:%02d</mtcoffset>\n",
        mtcOffset.h(), mtcOffset.m(), mtcOffset.s(),
        mtcOffset.f(), mtcOffset.sf());
      extSyncFlag.save(level, xml);
      xml.intTag(level, "genMTCSync", genMTCSync);
      xml.intTag(level, "genMCSync", genMCSync);
      xml.intTag(level, "genMMC", genMMC);
      xml.intTag(level, "acceptMTC", acceptMTC);
      xml.intTag(level, "acceptMMC", acceptMMC);
      xml.intTag(level, "acceptMC", acceptMC);

      xml.tag(level++, "score");
      if (!scoreBg.isEmpty())
            xml.strTag(level, "image", scoreBg.latin1());
      xml.tag(level--, "/score");

      xml.tag(level++, "printer type=%d", printerType);
      xml.strTag(level, "cmd", printerCommand.latin1());
      xml.strTag(level, "preview", previewCommand.latin1());
      xml.strTag(level, "file", printerFile.latin1());
      xml.tag(level--, "/printer");

      xml.tag(level++, "transport visible=%d", transport->isVisible());
      xml.put(level, "<geometry x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"></geometry>",
            transport->frameGeometry().x(),
            transport->frameGeometry().y(),
            transport->geometry().width(),
            transport->geometry().height());
      xml.put(level, "<handlecolor r=\"%d\" g=\"%d\" b=\"%d\"></handlecolor>",
	    transport->getHandleColor().red(),
      	    transport->getHandleColor().green(),
      	    transport->getHandleColor().blue());
      xml.tag(level--, "/transport");

      xml.tag(level++, "bigtime visible=%d", bigtime->isVisible());
      xml.put(level, "<geometry x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"></geometry>",
            bigtime->geometry().x(),
            bigtime->geometry().y(),
            bigtime->geometry().width(),
            bigtime->geometry().height());
      xml.put(level, "<foregroundcolor r=\"%d\" g=\"%d\" b=\"%d\"></foregroundcolor>",
	    bigtime->getFgColor().red(),
      	    bigtime->getFgColor().green(),
      	    bigtime->getFgColor().blue());
      xml.put(level, "<backgroundcolor r=\"%d\" g=\"%d\" b=\"%d\"></backgroundcolor>",
	    bigtime->getBgColor().red(),
      	    bigtime->getBgColor().green(),
      	    bigtime->getBgColor().blue());
      xml.tag(level--, "/bigtime");

      writeSerialPorts(level, xml);

      arranger->writeStatus(level, xml);
      seq->writeConfiguration(level, xml);

      DrumEdit::writeConfiguration(level, xml);
      PianoRoll::writeConfiguration(level, xml);
      MasterEdit::writeConfiguration(level, xml);
      Score::writeConfiguration(level, xml);
      WaveEdit::writeConfiguration(level, xml);

      writeMidiTransforms(level, xml);
      writeMidiInputTransforms(level, xml);
      writeSoftSynth(level, xml);
      xml.tag(level, "/configuration");
      }

//---------------------------------------------------------
//   configMidiSync
//---------------------------------------------------------

void MusE::configMidiSync()
      {
      if (!midiSyncConfig)
            midiSyncConfig = new MidiSyncConfig(this);
      midiSyncConfig->show();
      }

//---------------------------------------------------------
//   configAudioPorts
//---------------------------------------------------------

void MusE::configAudioPorts()
      {
      if (!audioConfig)
            audioConfig = new AudioConf(0);
      audioConfig->show();
      }

//---------------------------------------------------------
//   configMidiFile
//---------------------------------------------------------

void MusE::configMidiFile()
      {
      if (!midiFileConfig)
            midiFileConfig = new MidiFileConfig();
      midiFileConfig->show();
      }

//---------------------------------------------------------
//   MidiFileConfig
//    config properties of exported midi files
//---------------------------------------------------------

MidiFileConfig::MidiFileConfig()
   : QGroupBox(2, Horizontal, tr("Config exported Midi Files"), 0)
      {
      setCaption(tr("MusE: Config exported Midi Files"));
      QWidget* w = new QWidget(this);
      QGridLayout* grid = new QGridLayout(w);
      grid->setSpacing(5);

      QCheckBox* b1 = new QCheckBox(tr("Enable extended smf format"), w);
      b1->setChecked(extendedMidi);

      QLabel* l1 = new QLabel(tr("Division"), w);
      QComboBox* cb1 = new QComboBox(w);
      cb1->insertItem(QString("96"));
      cb1->insertItem(QString("192"));
      cb1->insertItem(QString("384"));
      int curItem = -1;
      switch(midiDivision) {
            case 96:    curItem = 0; break;
            case 192:   curItem = 1; break;
            case 384:   curItem = 2; break;
            }
      cb1->setCurrentItem(curItem);
      cb1->setFixedHeight(20);

      QLabel* l2 = new QLabel(tr("Copyright"), w);
      copyright  = new QLineEdit(w);
      copyright->setText(song->copyright());

      grid->addMultiCellWidget(b1, 0, 0, 0, 1);
      grid->addWidget(l1, 1, 0);
      grid->addWidget(cb1, 1, 1);
      grid->addWidget(l2, 2, 0);
      grid->addWidget(copyright, 2, 1);

      connect(copyright, SIGNAL(textChanged(const QString&)), song,
         SLOT(setCopyright(const QString&)));
      connect(b1,  SIGNAL(toggled(bool)), SLOT(setExtendedMidi(bool)));
      connect(cb1, SIGNAL(activated(int)), SLOT(setMidiDivision(int)));
      }

//---------------------------------------------------------
//   setMidiDivision
//---------------------------------------------------------

void MidiFileConfig::setMidiDivision(int index)
      {
      if (index < 0 || index >= 3)
            return;
      int divisions[3] = { 96, 192, 384 };
      midiDivision = divisions[index];
      }

//---------------------------------------------------------
//   setExtendedMidi
//---------------------------------------------------------

void MidiFileConfig::setExtendedMidi(bool f)
      {
      extendedMidi = f;
      }

//---------------------------------------------------------
//   configGlobalSettings
//---------------------------------------------------------

void MusE::configGlobalSettings()
      {
      if (!globalSettingsConfig)
            globalSettingsConfig = new GlobalSettingsConfig();
      globalSettingsConfig->show();
      }


