// ----
// ---- file   : NewInstrumentDialog.tks
// ---- author : Bastian Spiegel <bs@tkscript.de>
// ---- license: (c) 2007-2010 by Bastian Spiegel. 
// ----          Distributed under terms of the GNU LESSER GENERAL PUBLIC LICENSE (LGPL). See 
// ----          http://www.gnu.org/licenses/licenses.html#LGPL or COPYING for further information.
// ----
// ---- info   : 
// ----
// ---- created: 05-Nov-2007 
// ----
// ---- changed: 08Jan2008, 21Sep2009, 06Feb2010, 15Jul2010, 16Jul2010, 17Jul2010, 19Jul2010
// ----
// ----
// ----

module MNewInstrumentDialog;

use namespace ui;


class NewInstrumentDialog extends Dialog, ActionConsumer, ActionProvider {

   define int MIN_WIDTH = 200;
   define int MIN_HEIGHT = 70;

   define String ACTION_CREATE = "NewInstrumentDialog_CREATE";
   define String ACTION_CANCEL = "NewInstrumentDialog_CANCEL";

   protected ActionConsumer *recipient;

   protected XMLForm *xfm;

   protected ComboBox    *cm_type;
   protected TextField   *tf_name;
   protected FloatParam  *fp_polyphony;
   protected FloatParam  *fp_notelen;
   protected FloatParam  *fp_velocity;
   protected LayerSwitch *ls_type;
   protected Button      *bt_create;
   protected Button      *bt_cancel;
   protected TitledPanel *tp_typename;

   // Audio:
   protected ComboBox    *cm_audio_gen;
   protected LayerSwitch *ls_audio_gen;
   protected CheckBox    *cb_audio_gen_copyname;
   protected ComboBox    *cm_audio_sample;
   protected LayerSwitch *ls_audio_sample;
   protected CheckBox    *cb_audio_sample_autodialog;
   protected Button      *bt_audio_sample_selectfile;
   protected Label       *lb_audio_sample_dirname;
   protected Label       *lb_audio_sample_filename;
   protected CheckBox    *cb_audio_sample_copyname;
   protected ComboBox    *cm_audio_sample_waveform;

   // FX:
   protected ComboBox    *cm_fx_gen;

   // MIDI:
   protected ComboBox    *cm_midi_gen;
   protected LayerSwitch *ls_midi_gen;
   protected ComboBox    *cm_midi_gen_outdev;
   protected ComboBox    *cm_midi_gen_outch;

   // MIDI/Korg Radias:
   protected ComboBox    *cm_midikorgradias_gen;
   protected LayerSwitch *ls_midikorgradias_gen;
   protected ComboBox    *cm_midikorgradias_gen_outdev;
   protected ComboBox    *cm_midikorgradias_gen_outch;


   public static New(ActionConsumer _recipient) : NewInstrumentDialog {
      local NewInstrumentDialog d;
      if(d.initNewInstrumentDialog(_recipient))
      {
         return deref d;
      }
      else
      {
         return null;
      }
   }

   public virtual isPopup() : boolean {
      return true;
   }

   protected method getGeneratorByTypeAndIndex(String _typeName, int _idx) {
      ST_Generator *gen;
      int i = 0;
      foreach gen in (Global.song.generators)
      {
         if(_typeName == gen.getTypeName())
         {
            if(i == _idx)
            {
               return gen;
            }
            else
            {
               i++;
            }
         }
      }
      return null; // should never be reached
   }

   public method getSelectedPolyphony() : int {
      return fp_polyphony.getValue();
   }

   protected method getSelectedMIDIGenerator() : STX_MIDIGenerator {
      int idx = cm_midi_gen.getSelectedOption();
      if(0 == idx)
      {
         // Create MIDI generator from outputdevice+channel
         STX_MIDIGenerator midiGen <= new STX_MIDIGenerator();
         midiGen.setDeviceAndChannel(Global.GetMIDIOutDeviceByIndex(cm_midi_gen_outdev.getSelectedOption()),
                                     cm_midi_gen_outch.getSelectedOption()
                                     );
         midiGen.init(fp_polyphony.getValue());
         midiGen.setName(tf_name.getText());
         Global.song.addGenerator(deref midiGen);
         return midiGen;
      }
      else
      {
         return getGeneratorByTypeAndIndex(STX_MIDIGenerator.TYPE_MIDI, idx - 1);
      }
   }

   protected method getSelectedMIDIKorgRadiasGenerator() : STX_MIDIGeneratorKorgRadias {
      int idx = cm_midikorgradias_gen.getSelectedOption();
      if(0 == idx)
      {
         // Create MIDI/Korg Radias generator from outputdevice+channel
         STX_MIDIGeneratorKorgRadias korgRadiasGen <= new STX_MIDIGeneratorKorgRadias();
         korgRadiasGen.setDeviceAndChannel(Global.GetMIDIOutDeviceByIndex(cm_midikorgradias_gen_outdev.getSelectedOption()),
                                           cm_midikorgradias_gen_outch.getSelectedOption()
                                           );
         korgRadiasGen.init(fp_polyphony.getValue());
         korgRadiasGen.setName(tf_name.getText());
         Global.song.addGenerator(deref korgRadiasGen);
         return korgRadiasGen;
      }
      else
      {
         return getGeneratorByTypeAndIndex(STX_MIDIGeneratorKorgRadias.TYPE_KORGRADIAS, idx - 1);
      }
   }

   protected method getSelectedAudioGenerator() : STX_AudioGenerator {
      int idx = cm_audio_gen.getSelectedOption();
      if(0 == idx)
      {
         // Create audio generator from polyphony
         STX_AudioGenerator audioGen <= new STX_AudioGenerator();
         audioGen.init(int(fp_polyphony.getValue()));
         audioGen.setName(tf_name.getText());
         Global.song.addGenerator(deref audioGen);
         Global.HandleFXPatchUpdated();
         return audioGen;
      }
      else
      {
         return getGeneratorByTypeAndIndex(STX_AudioGenerator.TYPE_AUDIO, idx - 1);
      }
   }

   protected method getSelectedFXGenerator() : STX_FXGenerator {
      int idx = cm_fx_gen.getSelectedOption();
      if(0 == idx)
      {
         // Create FX generator
         STX_FXGenerator fxGen <= new STX_FXGenerator();
         fxGen.init(int(fp_polyphony.getValue()));
         fxGen.setName(tf_name.getText());
         Global.song.addGenerator(deref fxGen);
         return fxGen;
      }
      else
      {
         return getGeneratorByTypeAndIndex(STX_FXGenerator.TYPE_FX, idx - 1);
      }
   }

   public method getSelectedGenerator() : ST_Generator {
      switch(cm_type.getSelectedOption())
      {
         default:
         case 0: // MIDI
            return getSelectedMIDIGenerator();

         case 1: // MIDI/Korg Radias
            return getSelectedMIDIKorgRadiasGenerator();

         case 2: // AUDIO
            return getSelectedAudioGenerator();

         case 3: // FX
            return getSelectedFXGenerator();
      }
   }

   public method getSelectedName() : String {
      return tf_name.getText();
   }

   public method getSelectedDefaultNoteLength() : int {
      return fp_notelen.getValue();
   }

   public method getSelectedDefaultVelocity() : float {
      return fp_velocity.getValue();
   }

   public method getSelectedWaveform(StSample _sampleHint) : StWaveform {
      switch(cm_audio_sample.getSelectedOption())
      {
         default:
         case 0:
            // Create waveform+sample from file;
            StWaveform wf <= Waveforms.CreateFromFile(null, 
                                                      lb_audio_sample_dirname.getCaption() + "/" + lb_audio_sample_filename.getCaption(), 
                                                      null, // OUT file info string
                                                      _sampleHint
                                                      );
            return wf;

         case 1:
            // Create sample from existing waveform
            return Waveforms.GetByIdx(cm_audio_sample_waveform.getSelectedOption());

         case 2:
            // Create empty instrument
            return null;
      }
   }

   public method getSelectedInstrumentNameType() : boolean {
      // true=overwrite instrument name with sample name
      return cb_audio_sample_copyname.isSelected();
   }

   public method getSelectedGeneratorNameType() : boolean {
      // true=overwrite generator name with sample name
      if(0 == cm_audio_gen.getSelectedOption()) // Create new generator ?
      {
         return cb_audio_gen_copyname.isSelected();
      }
      else
      {
         return false;
      }
   }

   protected virtual layoutHierarchy() {
      Dialog::layoutHierarchy();

      recursiveBuildTabCycleLists();
   }

   protected method initNewInstrumentDialog(ActionConsumer _recipient) : boolean {

      initDialog();

      recipient <= _recipient;

      xfm <= XMLForm.New_PakFile("NewInstrumentDialog.xfm");
      if(null == xfm)
      {
         return false;
      }

      tf_name          <= xfm.findLayerById("tf_name");
      fp_polyphony     <= xfm.findLayerById("fp_polyphony");
      fp_notelen       <= xfm.findLayerById("fp_notelen");
      fp_velocity      <= xfm.findLayerById("fp_velocity");
      cm_type          <= xfm.findLayerById("cm_type");
      ls_type          <= xfm.findLayerById("ls_type");
      bt_create        <= xfm.findLayerById("bt_create");
      bt_cancel        <= xfm.findLayerById("bt_cancel");
      tp_typename      <= xfm.findLayerById("tp_typename");

      // Audio:
      cm_audio_gen                <= xfm.findLayerById("cm_audio_gen");
      ls_audio_gen                <= xfm.findLayerById("ls_audio_gen");
      cb_audio_gen_copyname       <= xfm.findLayerById("cb_audio_gen_copyname");
      cm_audio_sample             <= xfm.findLayerById("cm_audio_sample");
      ls_audio_sample             <= xfm.findLayerById("ls_audio_sample");
      cb_audio_sample_autodialog  <= xfm.findLayerById("cb_audio_sample_autodialog");
      bt_audio_sample_selectfile  <= xfm.findLayerById("bt_audio_sample_selectfile");
      lb_audio_sample_dirname     <= xfm.findLayerById("lb_audio_sample_dirname");
      lb_audio_sample_filename    <= xfm.findLayerById("lb_audio_sample_filename");
      cb_audio_sample_copyname    <= xfm.findLayerById("cb_audio_sample_copyname");
      cm_audio_sample_waveform    <= xfm.findLayerById("cm_audio_sample_waveform");

      // FX:
      cm_fx_gen <= xfm.findLayerById("cm_fx_gen");

      // MIDI:
      cm_midi_gen        <= xfm.findLayerById("cm_midi_gen");
      ls_midi_gen        <= xfm.findLayerById("ls_midi_gen");
      cm_midi_gen_outdev <= xfm.findLayerById("cm_midi_gen_outdev");
      cm_midi_gen_outch  <= xfm.findLayerById("cm_midi_gen_outch");

      // MIDI/Korg Radias:
      cm_midikorgradias_gen        <= xfm.findLayerById("cm_midikorgradias_gen");
      ls_midikorgradias_gen        <= xfm.findLayerById("ls_midikorgradias_gen");
      cm_midikorgradias_gen_outdev <= xfm.findLayerById("cm_midikorgradias_gen_outdev");
      cm_midikorgradias_gen_outch  <= xfm.findLayerById("cm_midikorgradias_gen_outch");

      initWindow(xfm, "New Instrument", 140, 140, 
                 570+UIConstants.WINDOW_BORDER_SIZE*2, 
                 450+WindowTitleBar.HEIGHT+UIConstants.WINDOW_BORDER_SIZE*2); // xxx hardcoded title height
      
      resizeToMinimum();
      resizeToMinimum();
      layoutHierarchy();
      
      return true;
   }

   public method isResizable() : boolean {
      return true;
   }

   // public method showNewInstrumentDialog() {
   //    

   //    Dialog::show();
   // }

   protected virtual preShow() {
      StringArray a;
      ST_Generator *gen;
      STX_MIDIOutDevice *outDev;
      StWaveform *wf;

      Dialog::preShow();

      // Update MIDI generator combobox options
      a.empty();
      a.add("<Create new generator>");
      foreach gen in Global.song.generators
      {
         if(STX_MIDIGenerator.TYPE_MIDI == gen.getTypeName())
         {
            a.add(gen.getFullName());
         }
      }
      cm_midi_gen.setOptions(a);

      a.empty();
      foreach outDev in (Global.out_devices)
      {
         a.add(outDev.getName());
      }
      cm_midi_gen_outdev.setOptions(a);
      cm_midikorgradias_gen_outdev.setOptions(a);
      

      // Update MIDI/Korg Radias generator combobox options
      a.empty();
      a.add("<Create new generator>");
      foreach gen in Global.song.generators
      {
         if(STX_MIDIGeneratorKorgRadias.TYPE_KORGRADIAS == gen.getTypeName())
         {
            a.add(gen.getFullName());
         }
      }
      cm_midikorgradias_gen.setOptions(a);


      // Update audio generator combobox options
      a.empty();
      a.add("<Create new generator>");
      foreach gen in Global.song.generators
      {
         if(STX_AudioGenerator.TYPE_AUDIO == gen.getTypeName())
         {
            a.add(gen.getFullName());
         }
      }
      cm_audio_gen.setOptions(a);

      // Update audio sample subpanels
      lb_audio_sample_dirname.setCaption("-");
      lb_audio_sample_filename.setCaption("-");
      
      a.empty();
      foreach wf in Waveforms.waveforms
      {
         a.add(wf.name);
      }
      cm_audio_sample_waveform.setOptions(a);

      // Update FX generator combobox options
      a.empty();
      a.add("<Create new generator>");
      foreach gen in Global.song.generators
      {
         if(STX_FXGenerator.TYPE_FX == gen.getTypeName())
         {
            a.add(gen.getFullName());
         }
      }
      cm_fx_gen.setOptions(a);

      resizeToMinimum();
      resizeToMinimum();
      layoutHierarchy();
   
   }

   public virtual postShow() {
      Dialog::postShow();

      UI.SetKeyboardFocus(cm_type);


      if(2 == cm_type.getSelectedOption()) // Audio?
      {
         if(0 == cm_audio_sample.getSelectedOption()) // Create sample from waveform / file ?
         {
            if(cb_audio_sample_autodialog.isSelected())
            {
               handleAudioSampleSelectFile();
            }
         }
      }
   }

   // public virtual hide() {
   //    Dialog::hide();
   // }

   protected method handleCreate() {

      // Validation
      if(2 == cm_type.getSelectedOption()) // Audio ?
      {
         if(0 == cm_audio_sample.getSelectedOption()) // Create waveform + sample from file
         {
            if("-" == lb_audio_sample_filename.getCaption())
            {
               Global.ShowErrorDialog("Error", "No sample file selected");
               return;
            }
         }
      }

      tf_name.stopEditing(false, false); // Do not provide new action to avoid recursion!
      hide();
      if(recipient instanceof ActionConsumer)
      {
         Action ac <= Action.New(ACTION_CREATE, this);
         recipient.consumeAction(ac);
         // Note: Do not add code below this line since the dialog instance may have been deleted by the recipient!
      }
   }

   protected method handleCancel() {
      hide();
      if(recipient instanceof ActionConsumer)
      {
         // Emit action to signalize "canceled" state
         Action ac <= Action.New(ACTION_CANCEL, this);
         recipient.consumeAction(ac);
         // Note: Do not add code below this line since the dialog instance may have been deleted by the recipient!
      }
   }

   public virtual onTriadKey(Key _k) : boolean {
      if(_k.pressed == 'c')
      {
         handleCancel();
         return true;
      }
   }

   public virtual onTriadKeyTimeout() {
      Global.ShowTriadKeyHelpDialog("lctrl-x ..", 
"
          c         :   Cancel dialog
"
                                    ,
                                    this);
   }

   public method onKey(Key _k) returns boolean {
      switch(_k.pressed)
      {
         case VKEY_RETURN:
            handleCreate();
            return true;

         case VKEY_ESCAPE:
            handleCancel();
            return true;
      }
      return Global.HandleKeyJazzKey(_k);
   }

   protected method handleTypeChanged() {
      int idx = cm_type.getSelectedOption();
      ls_type.switchToLayerNr(idx);

      tp_typename.setCaption(
         [
            STX_MIDIGenerator.TYPE_MIDI
            STX_MIDIGeneratorKorgRadias.TYPE_KORGRADIAS
            STX_AudioGenerator.TYPE_AUDIO
            STX_FXGenerator.TYPE_FX
          ] [idx]
                             );

      layoutHierarchy();
      resizeToMinimum();
      resizeToMinimum();
   }

   protected method handleMIDIGenTypeChanged() {
      int idx = cm_midi_gen.getSelectedOption();
      ls_midi_gen.switchToLayerNr(idx);
      layoutHierarchy();
      resizeToMinimum();
      resizeToMinimum();
   }

   protected method handleAudioGenTypeChanged() {
      int idx = cm_audio_gen.getSelectedOption();
      if(0 == idx)
      {
         ls_audio_gen.switchToLayerNr(0);
      }
      else
      {
         ls_audio_gen.switchToLayerNr(1);
      }
      layoutHierarchy();
      resizeToMinimum();
      resizeToMinimum();
   }

   protected method handleSampleTypeChanged() {
      int idx = cm_audio_sample.getSelectedOption();
      ls_audio_sample.switchToLayerNr(idx);
      layoutHierarchy();
      resizeToMinimum();
      resizeToMinimum();
   }

   protected method handleAudioSampleSelectFile() {
      FileDialog fd <= Global.filedlg_sample;
      fd.resetFileDialog(this);
      fd.setEnableHideAfterSelection(true);
      if(0 == fd.position_x)
      {
         fd.showNearLayer(this);
      }
      else
      {
         fd.show();
      }

      ///Main.BeginTemporarySampleKeyJazz();
      Global.b_keyjazz_tempsample = true;
   }

   protected method handleAudioSampleFileSelected(FileDialog fd) {
      String dirName  <= fd.getSelectedDirName();
      String fileName <= fd.getSelectedFileName();
      trace "xxx NewInstrumentDialog: ok, selected dir=\""+dirName+"\", file=\""+fileName+"\".";

      if(dirName.endsWith("/"))
      {
         String t;
         dirName.substring(0, dirName.length-2) => t;
         dirName <= t;
      }
      lb_audio_sample_dirname .setCaption(dirName);
      lb_audio_sample_filename.setCaption(fileName);

      relayoutAudioSampleFileLabels();

      UI.SetKeyboardFocus(bt_create);

      //Main.EndTemporarySampleKeyJazz();
      Global.b_keyjazz_tempsample = false;
   }

   protected method handleAudioSampleFileCancelled(FileDialog fd) {
      trace "xxx NewInstrumentDialog: file dialog was CANCELED.";
      lb_audio_sample_dirname.setCaption("-");
      lb_audio_sample_filename.setCaption("-");

      relayoutAudioSampleFileLabels();

      UI.SetKeyboardFocus(bt_cancel);

      ////Main.EndTemporarySampleKeyJazz();
      Global.b_keyjazz_tempsample = false;
   }

   protected method relayoutAudioSampleFileLabels() {
      Layer l <= lb_audio_sample_filename.getParent();
      l <= l.getParent();

      l.invalidateMinSizeCache();
      l.invalidateChildContainerMinSizeCaches();
      l.layoutHierarchy();
      l.redraw();
   }

   public method consumeAction(Action _action) returns boolean {

      String acName <= _action.getActionName();

      if(acName == TextField.ACTION_TEXTENTERED)
      {
         UI.SetKeyboardFocus(bt_create);
         return true;
      }

      ActionProvider ap <= _action.getActionProvider();
      switch(@(ap))
      {
         case @(cm_type):
            handleTypeChanged();
            return true;

         case @(cm_type):
            handleTypeChanged();
            return true;

         case @(cm_midi_gen):
            handleMIDIGenTypeChanged();
            return true;

         case @(cm_audio_gen):
            handleAudioGenTypeChanged();
            return true;

         case @(cm_audio_sample):
            handleSampleTypeChanged();
            return true;

         case @(bt_audio_sample_selectfile):
            handleAudioSampleSelectFile();
            return true;

         case @(bt_create):
            handleCreate();
            return true;

         case @(bt_cancel):
            handleCancel();
            return true;

         case @(Global.filedlg_sample):
            FileDialog fd <= ap;
            switch(acName)
            {
               case FileDialog.ACTION_OK:
                  handleAudioSampleFileSelected(fd);
                  break;

               case FileDialog.ACTION_CANCEL:
                  handleAudioSampleFileCancelled(fd);
                  break;
            }
            return true;
      }
      
      return true;
   }

}