//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: ctrlpanel.cpp,v 1.10 2004/04/24 14:58:52 wschweer Exp $
//  (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
//=========================================================

#include <stdio.h>
#include <list>

#include "ctrlpanel.h"
#include "ctrlcanvas.h"

#include <qlayout.h>
#include <qpushbutton.h>
#include <qpopupmenu.h>
#include <qlabel.h>
#include <qtooltip.h>
#include <qsizepolicy.h>

#include "globals.h"
#include "midictrl.h"
#include "instruments/minstrument.h"
#include "midiport.h"
#include "xml.h"
#include "icons.h"
#include "event.h"
#include "midieditor.h"
#include "track.h"
#include "part.h"
#include "midiedit/drummap.h"
#include "gconfig.h"

//---------------------------------------------------------
//   CtrlPanel
//---------------------------------------------------------

CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, const char* name)
   : QWidget(parent, name)
      {
      editor = e;
      setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
      QGridLayout* cgrid = new QGridLayout(this, 4, 1, 0);

      selCtrl = new QPushButton(tr("Sel"), this, "selCtrl");
      selCtrl->setFont(config.fonts[3]);
      selCtrl->setSizePolicy(
         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
      QToolTip::add(selCtrl, tr("select controller"));

      pop = new QPopupMenu(selCtrl);

      // destroy button
      QPushButton* destroy = new QPushButton(tr("x"), this, "destroy");
      destroy->setFont(config.fonts[3]);
      destroy->setSizePolicy(
         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
      QToolTip::add(destroy, tr("remove panel"));

      // Cursor Position
      connect(selCtrl, SIGNAL(pressed()), SLOT(ctrlPopup()));
      connect(destroy, SIGNAL(clicked()), SIGNAL(destroyPanel()));

      cgrid->addWidget(selCtrl, 0, 0);
      cgrid->addWidget(destroy,  2, 0);
      cgrid->setRowStretch(1,   50);
      }

//---------------------------------------------------------
//   setHeight
//---------------------------------------------------------

void CtrlPanel::setHeight(int h)
      {
      setFixedHeight(h);
      }

struct CI {
            QString s;
            bool used;
            CI(const QString& ss, bool u) : s(ss), used(u) {}
            };

//---------------------------------------------------------
//   ctrlPopup
//---------------------------------------------------------

void CtrlPanel::ctrlPopup()
      {
      //---------------------------------------------------
      // build list of midi controllers for current
      // MidiPort/channel
      //---------------------------------------------------

      PartList* parts  = editor->parts();
      Part* part       = parts->begin()->second;
      MidiTrack* track = (MidiTrack*)(part->track());
      int channel      = track->outChannel();
      MidiPort* port   = &midiPorts[track->outPort()];
      int curDrumInstrument = editor->curDrumInstrument();
      bool isDrum      = track->type() == Track::DRUM;

      pop->clear();
      pop->insertItem(tr("Velocity"), 1);

      MidiCtrlValListList* cll = port->controller();
      int min = channel << 24;
      int max = min + 0x1000000;

      std::list<CI> sList;
      typedef std::list<CI>::iterator isList;

      for (iMidiCtrlValList i = cll->lower_bound(min); i != cll->lower_bound(max); ++i) {
            MidiCtrlValList* cl = i->second;
            MidiController* c   = port->midiController(cl->num());
            // dont show drum specific controller if not a drum track
            if ((c->num() & 0xff) == 0xff) {
                  if (!isDrum)
                        continue;
                  // only show controller for curDrumInstrument:
                  if ((cl->num() & 0xff) != drumMap[curDrumInstrument].anote) {
                        continue;
                        }
                  }
            isList i = sList.begin();
            for (; i != sList.end(); ++i) {
                  if (i->s == c->name())
                        break;
                  }
            if (i == sList.end()) {
                  bool used = false;
                  for (iPart ip = parts->begin(); ip != parts->end(); ++ip) {
                        EventList* el = ip->second->events();
                        for (iEvent ie = el->begin(); ie != el->end(); ++ie) {
                              Event e = ie->second;
                              if ((e.type() == Controller) && (e.dataA() == cl->num())) {
                                    used = true;
                                    break;
                                    }
                              }
                        if (used)
                              break;
                        }
                  sList.push_back(CI(c->name(), used));
                  }
            }
      for (isList i = sList.begin(); i != sList.end(); ++i) {
            if (i->used)
                  pop->insertItem(QIconSet(*greendotIcon, *greendotIcon), i->s);
            else
                  pop->insertItem(i->s);
            }

      pop->insertItem(QIconSet(*configureIcon), tr("add new ..."), 2);
      int rv = pop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
      selCtrl->setDown(false);

      if (rv == -1)
            return;

      QString s = pop->text(rv);
      if (rv == 1) {    // special case velocity
            emit controllerChanged(CTRL_VELOCITY);
            }
      else if (rv == 2) {
            //
            // add new controller
            //
            QPopupMenu* pop1 = new QPopupMenu(this);
            pop1->setCheckable(false);
            //
            // populate popup with all controllers available for
            // current instrument
            //
            MidiInstrument* instr   = port->instrument();
            MidiControllerList* mcl = instr->controller();
            for (iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
                  pop1->insertItem((*ci)->name());
            int rv = pop1->exec(selCtrl->mapToGlobal(QPoint(0,0)));
            if (rv != -1) {
                  QString s = pop1->text(rv);
                  for (iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci) {
                        if ((*ci)->name() == s) {
                              MidiCtrlValList* vl = new MidiCtrlValList((*ci)->num());
                              cll->add(channel, vl);
                              emit controllerChanged(vl->num());
                              break;
                              }
                        }
                  }
            }
      else if (rv == -1)
            return;
      else {
            QString s = pop->text(rv);
            iMidiCtrlValList i = cll->begin();
            for (; i != cll->end(); ++i) {
                  MidiCtrlValList* cl = i->second;
                  MidiController* c   = port->midiController(cl->num());
                  int num = c->num();
                  if (c->name() == s) {
                        if (isDrum && ((num & 0xff) == 0xff))
                              num = (num & ~0xff) + drumMap[curDrumInstrument].anote;
                        emit controllerChanged(num);
                        break;
                        }
                  }
            if (i == cll->end()) {
                  printf("CtrlPanel: controller %s not found!", s.latin1());
                  }
            }
      }
