package net.mkonrad.synes.ctrl;

import java.io.IOException;

import javax.media.j3d.Node;
import javax.vecmath.Point3f;

import net.mkonrad.synes.data.AbstractGraph;
import net.mkonrad.synes.data.Beat;
import net.mkonrad.synes.data.BeatGraph;
import net.mkonrad.synes.data.Instrument;
import net.mkonrad.synes.data.Layer;
import net.mkonrad.synes.data.Modulator;
import net.mkonrad.synes.data.SynthGraph;
import net.mkonrad.synes.data.SynthInstrument;
import net.mkonrad.synes.data.SynthObj;
import net.mkonrad.synes.gui.elements.AbstractGraphLine;
import net.mkonrad.synes.gui.elements.SynthGraphLine;
import net.mkonrad.synes.gui.elements.instruments.InstrumentShape;
import net.mkonrad.synes.synth.SynthExt;
import net.mkonrad.synes.util.DbgTools;
import net.mkonrad.synes.util.ErrTools;

public class SynthLayerPickingCtrl extends AbstractLayerPickingCtrl
{
  //private BeatGraph _improBeatGraph = null;
  
  
  public SynthLayerPickingCtrl(CentralPickingCtrl pickCtrl)
  {
    super(pickCtrl);
  }

  public boolean moved(Node pickedObj, Point3f intercept, int mouseState)
  {
    if (_pickCtrl.getCurrGraphLine() != null)
    {      
      _pickCtrl.getCurrGraphLine().movedPointer(intercept);
      
      if (_coreCtrl.isOSCMode()
          && _coreCtrl.getCurrLayer().getType() == Layer.TYPE_SYNTH
          && _pickCtrl.getCurrGraph() != null)
      {
        updatePlayingGraph((SynthGraph)_pickCtrl.getCurrGraph());
      }
    }
    
    return true;
  }
  
  private void updatePlayingGraph(SynthGraph graph)
  {
    SynthObj synthObj = null;
    Modulator mod = graph.getModulator();
    boolean modInHand = false;
    if (mod == null)
    {
      mod = (Modulator)graph.getGraphLine().getPointerObj();  //we have the Modulator in the hand
      synthObj = graph.getSynthObj(0);
      modInHand = true;
    }
    else
    {
      synthObj = graph.getGraphLine().getPointerObj();  //we a SynthObj in the hand
    }

    SynthExt synth = synthObj.getSynth();
    
    try
    {
      if (synthObj != mod && synth != null)
      {
        //DbgTools.print("modifiying synth#" + synthObj.getId() + " with mod dist " + synthObj.getDistance() + " and mod amp " + mod.getAmp());
        synth.modSynthSynth(mod);
      }
    }
    catch (IOException e)
    {
      ErrTools.print(e);
    }
  }
  
  protected void createNewGraph(Point3f intercept)
  {
    DbgTools.print("Creating new SynthGraph");
    _pickCtrl.setState(CentralPickingCtrl.STATE_GRAPH_CREATE);
    
    //create new SynthObj & Modulator 
    SynthObj newSynthObj = createNewSynthObj(intercept);
    Modulator newMod = new Modulator(0.1f, new Point3f(intercept.x + 0.001f, intercept.y, intercept.z));
    
    //create new SynthGraph 
    SynthGraph synthGraph = new SynthGraph();
    _pickCtrl.setCurrGraphId(synthGraph.getId());
    synthGraph.setLayerLevel(_coreCtrl.getLayerSet().getCurrLayerLevel());
    synthGraph.addSynthObj(newSynthObj);
    newSynthObj.setGraph(synthGraph);

    //create new GraphLine
    SynthGraphLine graphLine = _pickCtrl.createGraphLine(synthGraph);
    _coreCtrl.getCurrLayer().addGraph(synthGraph);
    
    //play it
    if (_coreCtrl.isOSCMode() && _pickCtrl.getMouseEvent().isControlDown())
    {
      synthGraph.setState(SynthGraph.STATE_PERMANENTLY);
      playSynth(newSynthObj);
    }
    else
    {
      synthGraph.setState(SynthGraph.STATE_IMPRO);
    }
    
    //initialize "mouse over" for GraphLine
    startMouseOver(graphLine, newMod, intercept);
    
    //Add elements to the SceneGraph:
    _pickCtrl.addNewGraphElementsToScene(newSynthObj.getInstrumentShape().getBG());
  }
  
  protected SynthObj createNewSynthObj(Point3f intercept)
  {
    //get selected instrument
    Instrument currInstr = _pickCtrl.getCurrInstrument();
    
    //create new SynthObj
    SynthObj newSynthObj = new SynthObj(currInstr, 0.1f);
    
    //create shape according to the selected instrument and the beat's attributes
    newSynthObj.setInstrumentShape(
        currInstr.createInstrumentShape(newSynthObj, intercept)
    );
    
    DbgTools.print("Created new synth obj#" + newSynthObj.getId());
    
    return newSynthObj;
  }

  protected void addObjectToGraph(Point3f intercept)
  {
    SynthGraph synthGraph = (SynthGraph) _pickCtrl.getCurrGraph();
    
    if (synthGraph.getModulator() != null)  //we add a SynthObj, because there is already a Modulator
    {
      DbgTools.print("Adding synth to SynthGraph");
      //SynthObj newSynth = createNewSynthObj(intercept);
      SynthObj newSynth = _pickCtrl.getCurrGraphLine().getPointerObj();
      
      synthGraph.addSynthObj(newSynth);
      newSynth.setGraph(synthGraph);
      
      _pickCtrl.getCurrGraphLine().clicked(newSynth);
      newSynth.getInstrumentShape().getPrimitive().setPickable(true);
      
      newSynth.getInstrumentShape().getBG().detach();
      _pickCtrl.addNewGraphElementsToScene(newSynth.getInstrumentShape().getBG());
    }
    else  //we add a Modulator, because it has not been added yet
    {
      DbgTools.print("Adding modulator to SynthGraph");
      Modulator mod = (Modulator)_pickCtrl.getCurrGraphLine().getPointerObj();
      
      synthGraph.addModulator(mod);
      mod.setGraph(synthGraph);
      
      _pickCtrl.getCurrGraphLine().clicked(mod);
      mod.getInstrumentShape().getPrimitive().setPickable(true); 
      
      mod.getInstrumentShape().getBG().detach();
      _pickCtrl.addNewGraphElementsToScene(mod.getInstrumentShape().getBG());
    }
    
    //now we create a new SynthObj as pointer
    SynthObj newPointerObj = createNewSynthObj(intercept);
    
    if (_coreCtrl.isOSCMode() && synthGraph.getState() == SynthGraph.STATE_PERMANENTLY)
    {
      playSynth(newPointerObj);
    }
    
    _pickCtrl.getCurrGraphLine().changePointerObj(newPointerObj);
  }
  
  public void cancelGraphCreation()
  {
    AbstractGraphLine graphLine = _pickCtrl.getCurrGraphLine();
    
    if (graphLine == null)
      return;
      
    if (_pickCtrl.getCurrGraph().size() <= 1)
    {
      DbgTools.print("Canceling SynthGraph construction");
      
      if (_coreCtrl.isOSCMode())
      {
        try
        {
          if (((SynthGraph)_pickCtrl.getCurrGraph()).getSynthObj(0).getSynth() != null)
            ((SynthGraph)_pickCtrl.getCurrGraph()).getSynthObj(0).getSynth().release();
        } catch (IOException e)
        {
          ErrTools.print(e);
        }
      }
      
      graphLine.canceled();
      _pickCtrl.getCurrGraphLine().getBG().detach();
      _coreCtrl.getCurrLayer().removeGraph(_pickCtrl.getCurrGraphId());
      
      stopMouseOver(null);
    }
    else
    {
      cleanUp();
      
      graphLine.canceled();
      //DbgTools.print("Removing at index " + (_pickCtrl.getCurrGraph().size() - 1) + ": " + _pickCtrl.getCurrGraph().get(_pickCtrl.getCurrGraph().size() - 1));
      //_pickCtrl.getCurrGraph().remove(_pickCtrl.getCurrGraph().size() - 1);
      
      finishGraph(null);
    }
  }
  
  protected void cleanUp()
  {
    if (_coreCtrl.isOSCMode())
    {
      try
      {
        if (_pickCtrl.getCurrGraphLine().getPointerObj().getSynth() != null)
          _pickCtrl.getCurrGraphLine().getPointerObj().getSynth().release();
      } catch (IOException e)
      {
        ErrTools.print(e);
      }
    }
  }

  protected void finishGraph(Point3f intercept)
  {
    DbgTools.print("Finishing SynthGraph");
    
    stopMouseOver(intercept);
  }

  public void changeSynthObjInstr(SynthObj synthObj)
  {
    if (_coreCtrl.isOSCMode() && synthObj.getSynth() != null)
    {
      try
      {
        synthObj.getSynth().release();
        synthObj.setSynth(null);
        playSynth(synthObj);
      }
      catch (IOException e)
      {
        ErrTools.print(e);
      }
      
    }
  }
}
