#include "HandleUIControl.hpp"
#include "HandleMultiEdit.hpp"
#include "HandleWindow.hpp"
#include "Interpreter.hpp"
#include "Core.hpp"
#include <QtGui>

HandleUIControl::HandleUIControl() {
  ConstructProperties();
  SetupDefaults();
  widget = NULL;
}
  
HandleUIControl::~HandleUIControl() {
  if (widget) delete widget;
}

void HandleUIControl::SetEvalEngine(Interpreter *eval) {
  m_eval = eval;
}

// Need to handle initialization of "value" property
void HandleUIControl::UpdateState() {
  bool newwidget = false;
  if (HasChanged("style")) {
    if (widget) delete widget;
    widget = NULL;
    if (StringCheck("style","pushbutton")) {
      widget = new QPushButton(parentWidget->GetQtWidget());
      connect(widget,SIGNAL(clicked()),this,SLOT(clicked()));
    }
    if (StringCheck("style","radiobutton")) {
      widget = new QRadioButton(parentWidget->GetQtWidget());
      ((QRadioButton*) widget)->setAutoExclusive(false);
      connect(widget,SIGNAL(clicked()),this,SLOT(clicked()));
    }
    if (StringCheck("style","checkbox")) {
      widget = new QCheckBox(parentWidget->GetQtWidget());
      connect(widget,SIGNAL(clicked()),this,SLOT(clicked()));
    }
    if (StringCheck("style","toggle")) {
      widget = new QPushButton(parentWidget->GetQtWidget());
      ((QPushButton*) widget)->setCheckable(true);
      connect(widget,SIGNAL(clicked()),this,SLOT(clicked()));
    }
    if (StringCheck("style","slider")) {
      std::vector<double> sizevec(VectorPropertyLookup("position"));
      if (sizevec[3] > sizevec[2])
	widget = new QSlider(Qt::Vertical,parentWidget->GetQtWidget());
      else
	widget = new QSlider(Qt::Horizontal,parentWidget->GetQtWidget());
      ((QSlider*)widget)->setTracking(false);
      connect(widget,SIGNAL(valueChanged(int)),this,SLOT(clicked()));
    }
    if (StringCheck("style","popupmenu")) {
      widget = new QComboBox(parentWidget->GetQtWidget());
      connect(widget,SIGNAL(activated(int)),this,SLOT(clicked()));
      ((QComboBox*) widget)->setEditable(false);
    }
    if (StringCheck("style","listbox")) {
      widget = new QListWidget(parentWidget->GetQtWidget());
      connect(widget,SIGNAL(itemSelectionChanged()),this,SLOT(clicked()));
    }
    if (StringCheck("style","text")) {
      widget = new QLabel(parentWidget->GetQtWidget());
    }
    if (StringCheck("style","edit")) {
      double min(ScalarPropertyLookup("min"));
      double max(ScalarPropertyLookup("max"));
      if ((max-min) > 1) {
	widget = new HandleMultiEdit(parentWidget->GetQtWidget());
	widget->setObjectName("multiline");
      } else {
	widget = new QLineEdit(parentWidget->GetQtWidget());
	widget->setObjectName("singleline");
      }
      connect(widget,SIGNAL(editingFinished()),this,SLOT(clicked()));
    }
    if (widget)
      widget->show();
    ClearChanged("style");
    newwidget = true;
  }
  if (!widget) {
    ClearAllChanged();
    return;
  }
  if (HasChanged("position") || newwidget) {
    std::vector<double> sizevec(VectorPropertyLookup("position"));
    widget->setGeometry((int)sizevec[0],(int)sizevec[1],(int)sizevec[2],(int)sizevec[3]);
    ClearChanged("position");
  }
  if (HasChanged("string") || newwidget) {
    if (StringCheck("style","pushbutton") || 
	StringCheck("style","toggle")) {
      ((QPushButton*)widget)->setText(QString::fromStdString(StringPropertyLookup("string")));
    }
    if (StringCheck("style","radiobutton")) {
      ((QRadioButton*)widget)->setText(QString::fromStdString(StringPropertyLookup("string")));
    }
    if (StringCheck("style","checkbox")) {
      ((QCheckBox*)widget)->setText(QString::fromStdString(StringPropertyLookup("string")));
    }
    if (StringCheck("style","popupmenu")) {
      ((QComboBox*)widget)->clear();
      string txt(StringPropertyLookup("string"));
      vector<string> data;
      Tokenize(txt,data,"|");
      for (int i=0;i<data.size();i++)
	((QComboBox*)widget)->addItem(QString::fromStdString(data[i]));
    }
    if (StringCheck("style","listbox")) {
      ((QListWidget*)widget)->clear();
      string txt(StringPropertyLookup("string"));
      vector<string> data;
      Tokenize(txt,data,"|");
      for (int i=0;i<data.size();i++)
	((QListWidget*)widget)->addItem(QString::fromStdString(data[i]));
    }
    if (StringCheck("style","text")) {
      ((QLabel*)widget)->setText(QString::fromStdString(StringPropertyLookup("string")));
    }
    if (StringCheck("style","edit")) {
      if (widget->objectName() == "multiline")
	((HandleMultiEdit*)widget)->setPlainText(QString::fromStdString(StringPropertyLookup("string")));
      else
	((QLineEdit*)widget)->setText(QString::fromStdString(StringPropertyLookup("string")));
	  
    }
    ClearChanged("string");
  }
  if (HasChanged("tooltipstring") || newwidget) {
    widget->setToolTip(QString::fromStdString(StringPropertyLookup("tooltipstring")));
    ClearChanged("tooltipstring");
  }
  if (StringCheck("style","slider") && 
      (HasChanged("min") || HasChanged("max") || 
       HasChanged("sliderstep")  || newwidget)) {
    double min(ScalarPropertyLookup("min"));
    double max(ScalarPropertyLookup("max"));
    std::vector<double> steps(VectorPropertyLookup("sliderstep"));
    ((QSlider*)widget)->setMinimum(0);
    ((QSlider*)widget)->setMaximum((int)((max-min)/steps[0]));
    ((QSlider*)widget)->setSingleStep(1);
    ((QSlider*)widget)->setPageStep((int)(steps[1]));
    ((HPVector*) LookupProperty("value"))->Data(min+steps[0]*((QSlider*)widget)->value());
    ClearChanged("min");
    ClearChanged("max");
    ClearChanged("sliderstep");
  }
  if (StringCheck("style","listbox") &&
      (HasChanged("min") || HasChanged("max") || newwidget)) {
    double min(ScalarPropertyLookup("min"));
    double max(ScalarPropertyLookup("max"));
    if (max-min > 1)
      ((QListWidget*)widget)->setSelectionMode(QAbstractItemView::MultiSelection);
    else
      ((QListWidget*)widget)->setSelectionMode(QAbstractItemView::SingleSelection);
    ClearChanged("min");
    ClearChanged("max");
  }
  if (HasChanged("listboxtop") || newwidget) {
    if (StringCheck("style","listbox")) {
      double listtop(ScalarPropertyLookup("listboxtop"));
      ((QListWidget*)widget)->scrollToItem(((QListWidget*)widget)->item(listtop-1),
					   QAbstractItemView::PositionAtTop);
    }
    ClearChanged("listboxtop");
  }

  if (StringCheck("style","toggle") && 
      (HasChanged("value") || HasChanged("min") ||
       HasChanged("max") || newwidget)) {
    double min(ScalarPropertyLookup("min"));
    double max(ScalarPropertyLookup("max"));
    std::vector<double> value(VectorPropertyLookup("value"));
    if (value.size() > 0) {
      if (value[0] == min)
	((QPushButton*) widget)->setChecked(false);
      else if (value[0] == max) 
	((QPushButton*) widget)->setChecked(true);
    }
    ClearChanged("max");
    ClearChanged("min");
    ClearChanged("value");
  }

  if (StringCheck("style","radiobutton") && 
      (HasChanged("value") || HasChanged("min") ||
       HasChanged("max") || newwidget)) {
    double min(ScalarPropertyLookup("min"));
    double max(ScalarPropertyLookup("max"));
    std::vector<double> value(VectorPropertyLookup("value"));
    if (value.size() > 0) {
      if (value[0] == min)
	((QRadioButton*) widget)->setChecked(false);
      else if (value[0] == max) 
	((QRadioButton*) widget)->setChecked(true);
    }
    ClearChanged("max");
    ClearChanged("min");
    ClearChanged("value");
  }

  if (StringCheck("style","checkbox") && 
      (HasChanged("value") || HasChanged("min") ||
       HasChanged("max") || newwidget)) {
    double min(ScalarPropertyLookup("min"));
    double max(ScalarPropertyLookup("max"));
    std::vector<double> value(VectorPropertyLookup("value"));
    if (value.size() > 0) {
      if (value[0] == min)
	((QCheckBox*) widget)->setChecked(false);
      else if (value[0] == max) 
	((QCheckBox*) widget)->setChecked(true);
    }
    ClearChanged("max");
    ClearChanged("min");
    ClearChanged("value");
  }

  if (HasChanged("value") || newwidget) {
    if (StringCheck("style","slider")) {
      double min(ScalarPropertyLookup("min"));
      double max(ScalarPropertyLookup("max"));
      std::vector<double> steps(VectorPropertyLookup("sliderstep"));
      std::vector<double> value(VectorPropertyLookup("value"));
      if (value.size() > 0)
	((QSlider*)widget)->setValue((int)((value[0]-min)/steps[0]));
    }
    if (StringCheck("style","popupmenu")) {
      std::vector<double> value(VectorPropertyLookup("value"));
      ((QComboBox*)widget)->setCurrentIndex((int)(value[0]-1));
    }
    if (StringCheck("style","listbox")) {
      std::vector<double> value(VectorPropertyLookup("value"));
      ((QListWidget*)widget)->clearSelection();
      for (int i=0;i<value.size();i++) 
	((QListWidget*)widget)->setItemSelected(((QListWidget*)widget)->item((int)(value[i]-1)),true);
    }
    ClearChanged("value");
  }
}

void HandleUIControl::ConstructWidget(HandleWindow *f) {
  parentWidget = f;
  //   std::vector<double> sizevec(VectorPropertyLookup("position"));
  //   if (!widget) return;
  //   widget->setGeometry(sizevec[0],sizevec[1],sizevec[2],sizevec[3]);

  //   if (StringCheck("style","slider")) {
  //     double min(ScalarPropertyLookup("min"));
  //     double max(ScalarPropertyLookup("max"));
  //     std::vector<double> steps(VectorPropertyLookup("sliderstep"));
  //     ((QSlider*)widget)->setMinimum(0);
  //     ((QSlider*)widget)->setMaximum((max-min)/steps[0]);
  //     ((QSlider*)widget)->setSingleStep(1);
  //     ((QSlider*)widget)->setPageStep(steps[1]);
  //     ((HPVector*) LookupProperty("value"))->Data(min+steps[0]*((QSlider*)widget)->value());
  //   }
  //   widget->show();
}

void HandleUIControl::clicked() {
  if (StringCheck("style","slider") && widget) {
    double min(ScalarPropertyLookup("min"));
    double max(ScalarPropertyLookup("max"));
    std::vector<double> steps(VectorPropertyLookup("sliderstep"));
    ((HPVector*) LookupProperty("value"))->Data(min+steps[0]*((QSlider*)widget)->value());
    // No infinite loops, please
    ClearChanged("value");
  }
  if (StringCheck("style","popupmenu") && widget) {
    ((HPVector*) LookupProperty("value"))->Data(((QComboBox*)widget)->currentIndex()+1);
    ClearChanged("value");
  }
  if (StringCheck("style","listbox") && widget) {
    QList<QListWidgetItem*> selection(((QListWidget*) widget)->selectedItems());
    std::vector<double> selected;
    for (int i=0;i<selection.size();i++) 
      selected.push_back(((QListWidget*) widget)->row(selection[i])+1);
    ((HPVector*) LookupProperty("value"))->Data(selected);
    ClearChanged("value");
  }
  if (StringCheck("style","toggle") && widget) {
    if (((QPushButton*) widget)->isChecked())
      ((HPVector*) LookupProperty("value"))->Data(ScalarPropertyLookup("max"));
    else
      ((HPVector*) LookupProperty("value"))->Data(ScalarPropertyLookup("min"));
  }

  if (StringCheck("style","radiobutton") && widget) {
    if (((QRadioButton*) widget)->isChecked())
      ((HPVector*) LookupProperty("value"))->Data(ScalarPropertyLookup("max"));
    else
      ((HPVector*) LookupProperty("value"))->Data(ScalarPropertyLookup("min"));
  }

  if (StringCheck("style","checkbox") && widget) {
    if (((QCheckBox*) widget)->isChecked())
      ((HPVector*) LookupProperty("value"))->Data(ScalarPropertyLookup("max"));
    else
      ((HPVector*) LookupProperty("value"))->Data(ScalarPropertyLookup("min"));
  }

  if (StringCheck("style","edit") && widget) {
    if (widget->objectName() == "multiline") {
      SetStringDefault("string",((HandleMultiEdit*)widget)->toPlainText().toStdString());
    } else {
      SetStringDefault("string",((QLineEdit*)widget)->text().toStdString());
    }
  }

  m_eval->ExecuteLine(StringPropertyLookup("callback") + "\n");
}

void HandleUIControl::ConstructProperties() {
  //!
  //@Module UICONTROLPROPERTIES UI Control Properties
  //@@Section HANDLE
  //@@Usage
  //Below is a summary of the properties for user interface
  //controls.
  //\begin{itemize}
  //\item @|backgroundcolor| - @|colorspec| - The background color
  // for the widget.
  //\item @|busyaction| - Not used.
  //\item @|buttondownfcn| - Not used.
  //\item @|callback| - @|string| - the callback to execute when the 
  //GUI control does its action.  Clicking a button or moving a 
  //scroller will cause the callback to be executed.  Also, pressing 
  //enter in a text box causes the callback to be executed.
  //\item @|cdata| - an @|M x N x 3| array that represents an RGB image
  //to use as the truecolor image displayed on push bottons or toggle
  //buttons.  The values must be between 0 and 1.
  //\item @|children| - Not used.
  //\item @|createfcn| - Not used.
  //\item @|deletefcn| - Not used;
  //\item @|enable| - @|{'on','inactive','off'}| - For @|on| (the
  //default) the uicontrol behaves normally.  For inactive, it is not
  //operational, but looks the same as @|on|.  For @|off|, the
  //control is grayed out.
  //\item @|extent| - a read only property that contains the extent of
  //the text for the control.
  //\item @|fontangle| - @|{'normal','italic','oblique'}| - The angle of the fonts used
  // for text labels (e.g., tick labels).
  //\item @|fontsize| - @|scalar| - The size of fonts used for text labels (tick labels).
  //\item @|fontunits| - Not used.
  //\item @|fontname| - @|string| - The name of the font to use for the widget.
  //\item @|fontweight| - @|{'normal','bold','light','demi'}| - The weight of the font used
  //\item @|foregroundcolor| - @|colorspec| - the foreground color for text.
  //  \item @|handlevisibility| - Not used.
  //  \item @|hittest| - Not used.
  //\item @|horizontalalignment| - @|{'left','center','right}| - determines
  //the justification of text.
  //\item @|interruptible| - Not used.
  //\item @|keypressfcn| - @|functionspec| - a string or function handle
  // that is called when a key is pressed and a uicontrol object has focus.
  //\item @|listboxtop| - a scalar (used only by the listbox style of
  //uicontrols) that specifies which string appears at the top of the list
  //box.
  //\item @|max| - a scalar that specifies the largest value allowed
  //for the @|value| property.  The interpretation varies depending on
  //the type of the control
  //\begin{itemize}
  //\item @|check boxes| - specifies what @|value| is set to when the
  //check box is selected.
  //\item @|edit box| - if @|max-min>1| then the text box allows for
  //multiple lines of input.  Otherwise, it is a single line only.
  //\item @|list box| - if @|max-min>1| then multiple item selections
  //are allowed.  Otherwise, only single item selections are allowed.
  //\item @|radio buttons| - specifies what @|value| is set to when the
  //radio button is selected.
  //\item @|slider| - the maximum value the slider can take.
  //\item @|toggle button| - specifies what @|value| is set to when 
  //the toggle button is selected.
  //\end{itemize}
  //\item @|min| - a scalar that specifies the smallest value for the
  //@|value| property.  The interpretation of it depends on the type
  //of the control
  //\begin{itemize}
  //\item @|check boxes| - specifies what @|value| is set to when the
  //check box is not selected.
  //\item @|edit box| - if @|max-min>1| then the text box allows for
  //multiple lines of input.  Otherwise, it is a single line only.
  //\item @|list box| - if @|max-min>1| then multiple item selections
  //are allowed.  Otherwise, only single item selections are allowed.
  //\item @|radio buttons| - specifies what @|value| is set to when the
  //radio button is not selected.
  //\item @|slider| - the minimum value the slider can take.
  //\item @|toggle button| - specifies what @|value| is set to when 
  //the toggle button is not selected.
  //\end{itemize}
  //\item @|parent| - the handle of the parent object.
  //\item @|position| - size and location of the uicontrol as a 
  //four vector @|[left, bottom, width, height]|.  If @|width>height|
  //then sliders are horizontal, otherwise the slider is oriented
  //vertically.
  //\item @|selected| - @|{'on','off'}| - not used.
  //\item @|selectionhighlight| - @|{'on','off'}| - not used.
  //\item @|sliderstep| - a two vector @|[min_step max_step]|
  //that controls the amount the slider @|value| changes when
  //you click the mouse on the control.  If you click the arrow
  //for the slider, the value changes by @|min_step|, while if
  //you click the trough, the value changes by @|max_step|.  
  //Each value must be in the range @|[0,1]|, and is a percentage
  //of the range @|max-min|.
  //\item @|string| - @|string| - the text for the control.
  //\item @|style| - @|{'pushbutton','toggle','radiobutton','checkbox',
  //'edit','text','slider','frame','listbox','popupmenu'}|.
  //\item @|tag| - @|string| - user specified label.
  //\item @|tooltipstring| - @|string| the tooltip for the control.
  //\item @|type| - @|string| - the text is set to @|'uicontrol'|.
  //\item @|uicontextmenu| - @|handle| the handle of the @|uicontextmenu|
  //that shows up when you right-click over the control.
  //\item @|units| - not used.
  //\item @|userdata| - @|array| - any data you want to associate with the
  //control.
  //\item @|value| - The meaning of this property depends on the type of the
  //control:
  //\begin{itemize}
  //\item check box - set to @|max| when checked, and @|min| when off.
  //\item list box - set to a vector of indices corresponding to selected
  //items, with @|1| corresponding to the first item in the list.
  //\item pop up menu - set to the index of the item selected (starting with 1)
  //\item radio buttons - set to @|max| when selected, and set to @|min| when
  //not selected.
  //\item sliders - set to the value of the slider
  //\item toggle buttons - set to @|max| when selected, and set to @|min| when
  //not selected.
  //\item text controls, push buttons - do not use this property.
  //\end{itemize}
  //\item @|visible| - @|{'on','off'}| - controls whether the control is 
  //visible or not
  //\end{itemize}
  //!
  AddProperty(new HPColor,"backgroundcolor");
  AddProperty(new HPString,"busyaction");
  AddProperty(new HPString,"buttondownfcn");
  AddProperty(new HPString,"callback");
  AddProperty(new HPArray,"cdata");
  AddProperty(new HPHandles,"children");
  AddProperty(new HPString,"createfcn");
  AddProperty(new HPString,"deletefcn");
  AddProperty(new HPOnOffInactive,"enable");
  AddProperty(new HPFontAngle,"fontangle");
  AddProperty(new HPString,"fontname");
  AddProperty(new HPScalar,"fontsize");
  AddProperty(new HPFontUnits,"fontunits");
  AddProperty(new HPFontWeight,"fontweight");
  AddProperty(new HPColor,"foregroundcolor");
  AddProperty(new HPOnOff,"handlevisibility");
  AddProperty(new HPOnOff,"hittest");
  AddProperty(new HPAlignHoriz,"horizontalalignment");
  AddProperty(new HPOnOff,"interruptible");
  AddProperty(new HPString,"keypressfcn");
  AddProperty(new HPScalar,"listboxtop");
  AddProperty(new HPScalar,"max");
  AddProperty(new HPScalar,"min");
  AddProperty(new HPHandles,"parent");
  AddProperty(new HPFourVector,"position");
  AddProperty(new HPOnOff,"selected");
  AddProperty(new HPOnOff,"selectionhighlight");
  AddProperty(new HPTwoVector,"sliderstep");
  AddProperty(new HPString,"string");
  AddProperty(new HPWidgetString,"style");
  AddProperty(new HPString,"tag");
  AddProperty(new HPString,"tooltipstring");
  AddProperty(new HPString,"type");
  AddProperty(new HPHandles,"uicontextmenu");
  AddProperty(new HPUnits,"units");
  AddProperty(new HPArray,"userdata");
  AddProperty(new HPVector,"value");
}

void HandleUIControl::Hide() {
  if (widget) widget->hide();
}

void HandleUIControl::SetupDefaults() {
  SetThreeVectorDefault("backgroundcolor",0.6,0.6,0.6);
  SetStringDefault("enable","on");
  SetConstrainedStringDefault("fontangle","normal");
  SetStringDefault("fontname","helvetica");
  SetScalarDefault("fontsize",10);
  SetConstrainedStringDefault("fontunits","points");
  SetConstrainedStringDefault("fontweight","normal");
  SetThreeVectorDefault("foregroundcolor",0,0,0);
  SetConstrainedStringDefault("horizontalalignment","left");
  SetScalarDefault("listboxtop",1);
  SetScalarDefault("max",1);
  SetScalarDefault("min",0);
  ((HPVector*) LookupProperty("value"))->Data(0);
  SetFourVectorDefault("position",0,0,10,10);
  SetTwoVectorDefault("sliderstep",0.01,0.1);
  SetStringDefault("type","uicontrol");
  SetStringDefault("style","pushbutton");
}


syntax highlighted by Code2HTML, v. 0.9.1