/****************************************************************/
/**@file VideoSetting.cpp: 
 * Desctiption: Implementation of Hardware settings form.       *
 * Dependency: wxWindows					*
 ****************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
 #include <wx/wx.h>
#endif

#include "../library/wxTools.h"
#include "VideoSetting.h"
#include "RT_EXEC.h"


std::list<VideoSetting *> VideoSetting::Instances;

DEFINE_EVENT_TYPE(wxEVT_CAMERARESCHANGED)
DEFINE_EVENT_TYPE(wxEVT_CAMERACHANGED)
//DEFINE_EVENT_TYPE(wxEVT_NEW_FRAME_CAM1)


/** Event table for video settings. */
BEGIN_EVENT_TABLE(VideoSetting, wxFrame)
    EVT_BUTTON(ID_B_CANCEL,  VideoSetting::OnCancel)
    EVT_BUTTON(ID_B_DEFAULT, VideoSetting::OnDefault)
    EVT_BUTTON(ID_B_OK,      VideoSetting::OnOK)
    EVT_TEXT(ID_TEXTCTRL_THR,VideoSetting::OnChangedThreshold)
    EVT_BUTTON(ID_B_CHANGECAM,VideoSetting::OnChangeCamera)
    EVT_BUTTON(ID_B_CHANGERES,VideoSetting::OnChangeResolution)
    EVT_BUTTON(ID_B_CHANGERATE,VideoSetting::OnChangeRate)
    EVT_BUTTON(ID_B_PROPERTIES,VideoSetting::OnProperties)

    EVT_COMMAND(-1, wxEVT_CAMERARESCHANGED, VideoSetting::OnResolutionChanged) ///< Camera resolution has been switched
    WX_EVENT_TABLE_CONTROL_CONTAINER(VideoSetting)
END_EVENT_TABLE()

WX_DELEGATE_TO_CONTROL_CONTAINER(VideoSetting,wxWindow)


/**
 *  Constructor creates a frame. 
 *  @param[in] parent The pointer of the parent window  */
VideoSetting::VideoSetting(wxFrame *parent, CameraTool *NewCT, const char *TitleSuffix):
           wxFrame(parent, -1, wxString::Format(_("Video Settings%s"),TitleSuffix), wxDefaultPosition, wxSize(440,210),
           (wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL) & ~(wxMINIMIZE_BOX|wxMAXIMIZE_BOX|wxRESIZE_BORDER) ),
	   CT(NewCT)

{
    ////@begin VideoSetting member initialisation    
  itemPTimer = NULL;
  Szr_Timer = NULL;
  sTextTimer = NULL;
  sTextPer = NULL;
  TxtThreshold = NULL;
  itemPButton = NULL;
  itemFSizerBut = NULL;
  BtnOk = NULL;
  itemBCancel = NULL;
  itemBDef = NULL;    
    ////@end VideoSetting member initialisation
    
/// implementaiton
    m_container.SetContainerWindow(this); // CONTROL_CONTAINER should be initialised by this.
    Instances.push_back(this);

    VideoSetting* itemFrame1 = this;    

    itemPTimer = new wxPanel(itemFrame1, ID_PANEL_TIMER, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER|wxTAB_TRAVERSAL );    

    sTextTimer = new wxStaticText( itemPTimer, wxID_STATIC, _("THRESHOLD"), wxDefaultPosition, wxDefaultSize, 0 );
    sTextPer = new wxStaticText( itemPTimer, wxID_STATIC, _("Brigthness Threshold:\n(0-255)"), wxDefaultPosition, wxDefaultSize, 0 );

    Szr_Timer = new wxBoxSizer(wxVERTICAL);	
    itemPTimer->SetSizer(Szr_Timer);
    Szr_Timer->Add(sTextTimer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Szr_Timer->Add(sTextPer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);

    wxString Str;
    if(MRT.threshold)
      Str.Printf(wxT("%d"), (int)floor(MRT.threshold->GetDouble()));
    else
      Str = _T("???");
    TxtThreshold = new wxTextCtrl(itemPTimer, ID_TEXTCTRL_THR, Str, wxDefaultPosition, wxDefaultSize, 0);
    if(MRT.threshold==NULL) TxtThreshold->Enable(false);
    Szr_Timer->Add(TxtThreshold, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);

    itemPButton = new wxPanel( itemFrame1, ID_PANEL_BUTTON, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );    

	// panel with buttons
    BtnOk = new wxButton( itemPButton, ID_B_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBDef = new wxButton( itemPButton, ID_B_DEFAULT, _("Default"), wxDefaultPosition, wxDefaultSize, 0 );    
    itemBCancel = new wxButton( itemPButton, ID_B_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );

    itemFSizerBut = new wxFlexGridSizer(1,3,0,0);
    itemPButton->SetSizer(itemFSizerBut);
    itemFSizerBut->Add(BtnOk, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);
    itemFSizerBut->Add(itemBDef, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);     
    itemFSizerBut->Add(itemBCancel, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);    


    wxPanel *wxPConstants = new wxPanel(itemFrame1, ID_PANEL, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);

        // Box with parameters
    wxSize SzRes(wxDefaultSize);
    SzRes.SetWidth(60);
    Txt_Width = new wxStaticText(wxPConstants, wxID_STATIC, _("Width:"), wxDefaultPosition, wxDefaultSize, 0 );
    if(CT->Camera) Str.Printf( wxT("%d"), CT->Camera->GetWidth());
		 else Str= _T("N/A");
    Edt_Width = new wxTextCtrl(wxPConstants, ID_TEXTCTRL_WIDTH, Str, wxDefaultPosition, SzRes, 0 );
    Edt_Width->Enable(false);

    Txt_Height = new wxStaticText( wxPConstants, wxID_STATIC, _("Height:"), wxDefaultPosition, wxDefaultSize, 0 );
    if(CT->Camera) Str.Printf( wxT("%d"), CT->Camera->GetHeight());
	         else Str= _T("N/A");
    Edt_Height = new wxTextCtrl( wxPConstants, ID_TEXTCTRL_HEIGHT, Str, wxDefaultPosition, SzRes, 0 );
    Edt_Height->Enable(false);
  
    Txt_Depth = new wxStaticText( wxPConstants, wxID_STATIC, _("Image Depth:"), wxDefaultPosition, wxDefaultSize, 0 );
    if(CT->Camera) Str.Printf( wxT("%d"), CT->Camera->GetDepth());
		 else Str= _T("N/A");
    Edt_Depth = new wxTextCtrl( wxPConstants, ID_TEXTCTRL_DEPTH, Str, wxDefaultPosition, SzRes, 0 );
    Edt_Depth->Enable(false);

    Txt_FrameRate = new wxStaticText( wxPConstants, wxID_STATIC, _("Frame Rate:"), wxDefaultPosition, wxDefaultSize, 0 );
    if(CT->Camera) Str.Printf( wxT("%2g"), CT->Camera->GetFrameRate());
		 else Str= _T("N/A");
    Edt_FrameRate = new wxTextCtrl( wxPConstants, ID_TEXTCTRL_FRAMERATE, Str, wxDefaultPosition, SzRes, 0 );
    Edt_FrameRate->Enable(false);

             // arrange widgets
    wxFlexGridSizer *Sz_Parameters = new wxFlexGridSizer(4,2,0,0);
    wxPConstants->SetSizer(Sz_Parameters);    

    Sz_Parameters->Add(Txt_Width, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Edt_Width, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Txt_Height, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Edt_Height, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Txt_Depth, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Edt_Depth, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Txt_FrameRate, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
    Sz_Parameters->Add(Edt_FrameRate, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
      /* ~Box with parameters */
    
    BtnChangeRes = new wxButton(this,ID_B_CHANGERES, _("Select Video Mode"), wxDefaultPosition, wxDefaultSize, 0);    
    BtnChangeCam = new wxButton(this,ID_B_CHANGECAM, _("Select Camera"), wxDefaultPosition, wxDefaultSize, 0);
    BtnChangeRate = new wxButton(this,ID_B_CHANGERATE, _("Change Rate"), wxDefaultPosition, wxDefaultSize, 0);
    BtnProperties = new wxButton(this,ID_B_PROPERTIES, _("Properties"), wxDefaultPosition, wxDefaultSize, 0);
    wxSize SzResFinal = BtnChangeRes->GetSize();
    SzRes = BtnChangeCam->GetSize();
    if(SzResFinal.GetWidth() < SzRes.GetWidth()) SzResFinal.SetWidth(SzRes.GetWidth());
    SzRes = BtnChangeRate->GetSize();
    if(SzResFinal.GetWidth() < SzRes.GetWidth()) SzResFinal.SetWidth(SzRes.GetWidth());
    SzRes = BtnProperties->GetSize();
    if(SzResFinal.GetWidth() < SzRes.GetWidth()) SzResFinal.SetWidth(SzRes.GetWidth());
    BtnChangeRes->SetSize(SzResFinal);
    BtnChangeCam->SetSize(SzResFinal);
    BtnChangeRate->SetSize(SzResFinal);
    BtnProperties->SetSize(SzResFinal);
       
    BtnChangeRes->Enable(CT->Camera!=NULL);
    BtnChangeRate->Enable(CT->Camera!=NULL);
    BtnProperties->Enable(CT->Camera!=NULL);

    wxSizer *SzrBtns = new wxBoxSizer(wxVERTICAL);
    SzrBtns->Add(BtnChangeCam); //,0,wxADJUST_MINSIZE);
    SzrBtns->Add(10,10);
    SzrBtns->Add(BtnChangeRes); //,0,wxADJUST_MINSIZE);
    SzrBtns->Add(10,10);
    SzrBtns->Add(BtnChangeRate); //,0,wxADJUST_MINSIZE);
    SzrBtns->Add(10,10);
    SzrBtns->Add(BtnProperties); //,0,wxADJUST_MINSIZE);

	//create main layout of a form
    wxSizer *sizerParams = new wxBoxSizer(wxHORIZONTAL);
    sizerParams->Add(itemPTimer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);
    sizerParams->Add(wxPConstants, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);
    sizerParams->Add(SzrBtns, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxSizer *sizerDown = new wxBoxSizer(wxVERTICAL);    
    itemFrame1->SetSizer(sizerDown);
    sizerDown->Add(sizerParams, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);
    sizerDown->Add(itemPButton, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);

	//other form settings
    SetBackgroundColour(itemPButton->GetBackgroundColour());
    SetIcon(parent->GetIcon());  //prefer same icons for all opened frames

    SetAutoLayout(true);
    Layout();    
}


/** Cancel all changes. Processes cancel button. Close the frame.
 *  @param[in] event Unused event   */
void VideoSetting::OnCancel(wxCommandEvent& WXUNUSED(event))
{
  Close(true);
}


/** Push a new value into a mainFramePtr->GetCamPlate()->SetPreviewTimer
 *  Processes OK button.    
 *  @param[in] event Unused event   */
void VideoSetting::OnOK(wxCommandEvent& WXUNUSED(event))
{
  if(MRT.threshold==NULL) {Close(true);return;}

  wxString str = TxtThreshold->GetValue();

  if (str.IsNumber())
    {
    long threshold;
    str.ToLong(&threshold);
    MRT.threshold->SetDouble(threshold);
    Close(true);
    } 
  else
    {
    wxString msg;
    msg.Printf(wxT(_("Possible you entered a wrong value\nPlease try again")));
    wxMessageBox(msg, _("Input Error"), wxOK|wxICON_EXCLAMATION, this);
    }  
}


/** Set default value of all video settings timer.
 *  @param[in] event Unused event */
void VideoSetting::OnDefault(wxCommandEvent& WXUNUSED(event))
{
    wxString timeStr;
    timeStr.Printf( wxT("%d"), CameraTool::DEFAULT_THR );
    TxtThreshold->SetValue(timeStr);       
}


/** Check given Thresold value */
void VideoSetting::OnChangedThreshold(wxCommandEvent& WXUNUSED(event))
{
  CheckDoubleTxt(TxtThreshold);
}


/** Allow user to manually change camera. */
void VideoSetting::OnChangeCamera(wxCommandEvent& WXUNUSED(event))
{
  if(CT->Camera) CT->Camera->Stop();
  if( CT == &MRT.CT)
    MRT.Hook2Drv(CamRtExec::SEL_CAM|CamRtExec::SEL_FORCE);
  else
    MRT.Hook2Drv(CamRtExec::SEL_CAM2|CamRtExec::SEL_FORCE);
  if(CT->Camera) CT->Camera->Start();
  BtnChangeRes->Enable(CT->Camera!=NULL);
  BtnChangeRate->Enable(CT->Camera!=NULL);
  BtnProperties->Enable(CT->Camera!=NULL);
  RefreshCameraProp();

    /* Emit notification about camera change. */
  wxCommandEvent event(wxEVT_CAMERACHANGED,GetId());
  event.SetEventObject(this);  
  //event.SetText( wxT("Camera") );  // Give it some contents (I hope that this is not necessary)
  GetEventHandler()->ProcessEvent(event);
}


/** Allow user to manually change resolution of a camera. */
void VideoSetting::OnChangeResolution(wxCommandEvent& WXUNUSED(event))
{
  if(CT->Camera)
    {
    CT->Camera->Stop();
    CT->Camera->ChangeResolution();    
    CT->Camera->Start();

		/* Emit notification about resolution change. */
    wxCommandEvent event(wxEVT_CAMERARESCHANGED,GetId());
    event.SetEventObject(this);  
    // event.SetText( wxT("Resolution") );  // Give it some contents (I hope that this is not necessary).
    GetEventHandler()->ProcessEvent(event);
    
    // RefreshCameraProp(); - This procedure is actually called through event, here is placed as reminder.
    }
  else
    BtnChangeRes->Enable(false);
}


/** Allow user to manually change frame rate. */
void VideoSetting::OnChangeRate(wxCommandEvent& WXUNUSED(event))
{
  if(CT->Camera)
  {
    wxString Str(_("Frame rate of camera [fps]:\n"));
    if(CT->Camera->GetFrameRate(1)>0 && CT->Camera->GetFrameRate(2)>0)
      Str += wxString::Format(wxT(_("Supported range [%.2g;%2g].\n")),
		    CT->Camera->GetFrameRate(2),CT->Camera->GetFrameRate(1));    

    wxTextEntryDialog dialog(this, Str, _("Set Frame Rate"),
         wxString::Format(wxT("%.2g"), CT->Camera->GetFrameRate()),
                                wxOK | wxCANCEL);
    dialog.SetIcon(GetIcon());

    if(dialog.ShowModal() == wxID_OK)
    {
      double NewFrameRate;
      wxString valText = dialog.GetValue();

      if( !valText.ToDouble(&NewFrameRate) || NewFrameRate <= 0)
      {    
        wxMessageBox(_("Invalid entry was typed\n") , _("Error"), wxOK | wxICON_ERROR, this);
        return;
      }

      if(abs(NewFrameRate-CT->Camera->GetFrameRate())<1e-3)
	return;		// No change, don't fiddle with camera.

      CT->Camera->Stop();
      CT->Camera->SelectVideoMode(CT->Camera->GetWidth(),CT->Camera->GetHeight(),CT->Camera->GetDepth(),NewFrameRate);
      CT->Camera->Start();

        /* Emit notification about resolution change. */
      wxCommandEvent event(wxEVT_CAMERARESCHANGED,GetId());
      event.SetEventObject(this);  
      //  event.SetText( wxT("Resolution") );  // Give it some contents
      GetEventHandler()->ProcessEvent(event);
    }
  }
  else		// The button is accicentally enabled, disable it.
  {
    BtnChangeRate->Enable(false);
  }
}


/** Allow user to manually change frame rate. */
void VideoSetting::OnProperties(wxCommandEvent& WXUNUSED(event))
{
  if(CT->Camera)
  {
    HWND hwnd = (HWND)GetHWND();

    BtnProperties->Enable(false);    
    CT->Camera->ShowPropertyPage(reinterpret_cast<size_t>(hwnd));
    BtnProperties->Enable(true);
  }
  else		// The button is accicentally enabled, disable it.
  {
    BtnProperties->Enable(false);
  }
}


/** Catch message about camera change and update a form according to this change. */
void VideoSetting::OnResolutionChanged(wxCommandEvent & event)
{
  event.Skip();		//Allow this event to go further to the main application window.
  RefreshCameraProp();
}


/** Repaint edit boxes for Width, Height and Depth. */
void VideoSetting::RefreshCameraProp(void)
{
wxString Str;

  if(CT->Camera) Str.Printf( wxT("%d"), CT->Camera->GetWidth());
 	       else Str= _T("N/A");  
  Edt_Width->SetValue(Str);
  if(CT->Camera) Str.Printf( wxT("%d"), CT->Camera->GetHeight());
	       else Str= _T("N/A");
  Edt_Height->SetValue(Str);
  if(CT->Camera) Str.Printf( wxT("%d"), CT->Camera->GetDepth());
		else Str= _T("N/A");
  Edt_Depth->SetValue(Str);
  if(CT->Camera) Str.Printf( wxT("%2.2g"), CT->Camera->GetFrameRate());
		else Str= _T("N/A");
  Edt_FrameRate->SetValue(Str);

  TxtThreshold->Enable(MRT.threshold!=NULL);
  if(MRT.threshold!=NULL && CT->Camera!=NULL)
    {
    wxString str = TxtThreshold->GetValue();
    if(str[0]=='?')	//Previously selected camera didn't work, now return correct value to editbox.
      {
      Str.Printf(wxT("%d"), (int)floor(MRT.threshold->GetDouble()));
      TxtThreshold->SetValue(Str);
      }
    }
}