package net.mkonrad.synes.gui.elements;

import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.text.AttributedString;
import java.util.ArrayList;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Node;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;

import com.xith.java3d.overlay.LabelOverlay;

import de.sciss.jcollider.JCollider;

import net.mkonrad.synes.data.Instrument;
import net.mkonrad.synes.data.InstrumentCabinet;
import net.mkonrad.synes.data.Layer;
import net.mkonrad.synes.gui.Canvas3DExt;
import net.mkonrad.synes.gui.SceneCore;
import net.mkonrad.synes.gui.style.Colors;
import net.mkonrad.synes.util.Common3DTools;
import net.mkonrad.synes.util.ErrTools;

public class HUDOverlay
{
  private SceneCore _sceneCore;
  private Canvas3DExt _canvas3D;
  private TransformGroup _viewTG;
  private BranchGroup _instrChoiceBG;
  private Color _defaultColor;
  private Font _defaultFont;
  private ArrayList<LabelOverlayExt> _instrLbls;
  private LabelOverlay _orbitOnOffLbl;
  private LabelOverlay _layerInfoLbl;
  private LabelOverlay _levelLbl;
  private BranchGroup _loadingLblBG;
  private int _selectedInstrIndex;
  
  public HUDOverlay(SceneCore sceneCore)
  {
    _sceneCore = sceneCore;
    _canvas3D = _sceneCore.getCanvas3D();
    _viewTG = _sceneCore.getViewingPlatform().getViewPlatformTransform();
    
    _selectedInstrIndex = 0;
    _instrLbls = new ArrayList<LabelOverlayExt>();
    
    _defaultColor = new Color(Colors.text.x, Colors.text.y, Colors.text.z);
    _defaultFont = new Font("Arial", Font.BOLD, 14);
  }

  public void display()
  {
    _viewTG.addChild(createTitle());
    _viewTG.addChild(createLayerInfo());
    
    _instrChoiceBG = new BranchGroup();
    //_instrChoiceBG.setCapability(BranchGroup.ALLOW_DETACH);
    _instrChoiceBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
    _instrChoiceBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
    _instrChoiceBG.addChild(createInstrChoice());
    _viewTG.addChild(_instrChoiceBG);
    
    _viewTG.addChild(createOrbitDisplay());
    _viewTG.addChild(createLevelDisplay());
  }
  
  public void displayLoadingMsg()
  {
    _viewTG.addChild(createLoadingMsg());
  }
  
  public void hideLoadingMsg()
  {
    _viewTG.removeChild(_loadingLblBG);
  }
  
  public void updateAvailableInstr()
  {
    _instrChoiceBG.removeAllChildren();
    _instrChoiceBG.addChild(createInstrChoice());
  }
  
  public void updateInstrChoice(int index)
  {
    try
    {
      if (_selectedInstrIndex < _instrLbls.size())
        _instrLbls.get(_selectedInstrIndex).setSelected(false);
      _instrLbls.get(index).setSelected(true);
      _selectedInstrIndex = index;
    } catch (IndexOutOfBoundsException e)
    {
      ErrTools.print("Could not update HUD: Label from Instrument #" + index + " not found!");
    }
  }
  
  public void updateOrbitStatus(boolean on)
  {
    _orbitOnOffLbl.setText((on ? "On" : "Off"));
  }
  
  public void updateLayerInfo()
  {
    _layerInfoLbl.setText(getLayerInfoText());
    _levelLbl.setText(getLevelInfoText());
  }
  
  private String getLayerInfoText()
  {
    return (_sceneCore.getCurrLayer().getType() == Layer.TYPE_SEQUENCER ?
        "SEQ-Layer" : "SYNTH-Layer");
  }
  
  private BranchGroup createLayerInfo()
  {
    _layerInfoLbl = new LabelOverlay(
        _canvas3D, new Rectangle(700, 10, 100, 20),
        getLayerInfoText(),
        _defaultFont,
        _defaultColor
    );

    return _layerInfoLbl.getRoot();
  }
  
  private BranchGroup createLoadingMsg()
  {
    String msg;
    int x, w;
    if (!JCollider.isWindows)
    {
      msg = "Booting SC server / connecting...";
      x = 250;
      w = 400;
    }
    else
    {
      msg = "You are running Windows! Better run the start-script now: synesthesia\\SuperCollider\\run-win.sc";
      x = 50;
      w = 700;
    }
    
    LabelOverlay loadingMsg = new LabelOverlay(
        _canvas3D, new Rectangle(x, 280, w, 20),
        msg,
        _defaultFont,
        _defaultColor
    );
    
    _loadingLblBG = Common3DTools.wrapInBG(loadingMsg.getRoot(), new int [] { BranchGroup.ALLOW_DETACH });
    
    return _loadingLblBG;
  }
  
  private BranchGroup createInstrChoice()
  {
    int lblW = 100;
    int lblH = 20;
    
    BranchGroup bg = new BranchGroup();
    bg.setCapability(BranchGroup.ALLOW_DETACH);
    bg.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
    
    _instrLbls.clear();
    _canvas3D.clearInstrImgs();
    
    ArrayList<Instrument> cab = SceneCore.getInstrCabinet().get(_sceneCore.getCurrLayer().getType());
    
    int x, y;
    Color textColor = new Color(Colors.text.x, Colors.text.y, Colors.text.z);
    for (int i = 0; i < cab.size(); i++)
    {
      x = 30 + i * lblW;
      y = 35;
      
      Instrument instr = cab.get(i);
      
      //Color3f instrCol = instr.getColor();
      String instrName = instr.getName();
      instrName = instrName.replaceFirst("synes_", "");
      LabelOverlayExt label = new LabelOverlayExt(_canvas3D,
          new Rectangle(x, y, lblW, lblH),
          instr.getKey() + ": " + instrName,
          _defaultFont,
          textColor,
          (_selectedInstrIndex == i)
      );
      
      _canvas3D.addInstrImg(x - 20, y + 2, "icon." + instr.getIcon());
      _instrLbls.add(label);
      bg.addChild(label.getRoot());
    }
    
    return bg;
  }

  private BranchGroup createTitle()
  {
    LabelOverlay label = new LabelOverlay(_canvas3D, new Rectangle(10, 10, 200, 20), "SYNCUBE", _defaultFont, _defaultColor);
    
    return label.getRoot();
  }
  
  private Node createOrbitDisplay()
  {
    boolean status = _sceneCore.getGuiCtrl().getOrbitControl().getEnable();
    
    LabelOverlay labelTitle = new LabelOverlay(_canvas3D, new Rectangle(10, 570, 200, 20), "Orbit", _defaultFont, _defaultColor);
    _orbitOnOffLbl =  new LabelOverlay(_canvas3D, new Rectangle(50, 570, 200, 20), (status ? "On" : "Off"), _defaultFont, _defaultColor);
    BranchGroup onOffBG = _orbitOnOffLbl.getRoot();
    onOffBG.setCapability(BranchGroup.ALLOW_DETACH);
    _viewTG.addChild(onOffBG);
    
    return labelTitle.getRoot();
  }
  
  private BranchGroup createLevelDisplay()
  {
    LabelOverlay label = new LabelOverlay(_canvas3D, new Rectangle(700, 570, 200, 20), "Level", _defaultFont, _defaultColor);
    _levelLbl =  new LabelOverlay(_canvas3D, new Rectangle(750, 570, 200, 20), getLevelInfoText(), _defaultFont, _defaultColor);
    BranchGroup lvlBG = _levelLbl.getRoot();
    lvlBG.setCapability(BranchGroup.ALLOW_DETACH);
    _viewTG.addChild(lvlBG);
    
    return label.getRoot();
  }
  
  private String getLevelInfoText()
  {
    return new String("" + (int)(_sceneCore.getCurrLayer().getId() + 1));
  }
}
