#ifndef kcApp_h
#define kcApp_h

extern "C" struct cmApBufState_str; 

class Fl_Menu_Bar;
class Fl_HSplitter;
class Fl_Text_Buffer;
class Fl_Text_Display;
class Fl_Box;
class Fl_Tabs;
class Fl_Check_Button;
class Fl_Value_Slider;
class Fl_Menu_Button;
class Fl_File_Btn;
class Fl_Select_Browser;
class Fl_Valuator;
class Fl_Value_Input;
class Fl_Progress;

  enum
  {
    kOkKmRC,
    kEngFailKmRC,
    kMemFailKmRC,
    kFileSysFailKmRC,
    kQueueFailKmRC,
    kTextSysFailKmRC,    
    kPrefsFailKmRC,
    kMlistLoadFailKmRC,
    kJsonFailKmRC,
    kDeserialFailKmRC,
    kPrintQueFailKmRC,
  
  };

class kcApp : public Fl_Double_Window, public tlCtlRspdr
{
public:
  typedef unsigned kcKmRC_t;

  kcApp(cmCtx_t* ctx, cmPrH_t prH, cmTsMp1cH_t printQH, int w, int h, const cmChar_t* title, cmAiH_t aiH, int argc, char* argv[] );
  virtual ~kcApp();

  void resize(int x, int y, int w, int h);

  virtual void tlCtlNewTimeLineFile( tlCtl* tlCtl, const cmChar_t* fn );
  virtual void tlCtlNewScoreFile(    tlCtl* tlCtl, const cmChar_t* fn );


  void print(  const char* fmt, ... );
  void vprint( const char* fmt, va_list vl );


private:
  enum
  {
    kMenuH   = 30,
    kStatusH = 30,
    kIndH    = 25,
    kIndW    = 25,
    
    kSsPhaseMax = 20
  };


  enum
  {
    kSldrTypeId,
    kNumbTypeId,
    kTextTypeId,
    kButnTypeId,
    kChckTypeId,
    kLablTypeId,
    kFnamTypeId,
    kMlstTypeId,
    kMetrTypeId,
    kTmlnTypeId,
    kScorTypeId,
    kTksbTypeId,
    kTksrTypeId,
    kTwodTypeId,

    kSldrMinArgIdx = 0,
    kSldrMaxArgIdx = 1,
    kSldrStpArgIdx = 2,
    kSldrValArgIdx = 3,
    kSldrLblArgIdx = 4,
    kSldrVarCnt    = 5,

    kTextValArgIdx = 0,
    kTextLblArgIdx = 1,
    kTextVarCnt    = 2,

    kButnValArgIdx = 0,
    kButnLblArgIdx = 1,
    kButnVarCnt    = 2,

    kLablValArgIdx  = 0,
    kLablAlignArgIdx= 1,
    kLablVarCnt     = 2,

    kChckValArgIdx  = 0,
    kChckLblArgIdx  = 1,
    kChckVarCnt     = 2,

    kFnamValArgIdx = 0,
    kFnamPatArgIdx = 1,
    kFnamDirArgIdx = 2,
    kFnamVarCnt    = 3,

    kMlstHgtArgIdx = 0,
    kMlstSelArgIdx = 1,
    kMlstLstArgIdx = 2,
    kMlstVarCnt    = 3,

    kMetrMinArgIdx = 0,
    kMetrMaxArgIdx = 1,
    kMetrValArgIdx = 2,
    kMetrLblArgIdx = 3,
    kMetrVarCnt    = 4,

    kTmlnFileArgIdx= 0,
    kTmlnPathArgIdx= 1,
    kTmlnSelArgIdx = 2,
    kTmlnMeasArgIdx= 3,
    kTmlnCursArgIdx= 4,
    kTmlnVarCnt    = 5,

    kScorFileArgIdx    = 0,
    kScorSelArgIdx     = 1,
    kScorSmpIdxArgIdx  = 2,
    kScorPitchArgIdx   = 3,
    kScorVelArgIdx     = 4,
    kScorLocIdxArgIdx  = 5,
    kScorEvtIdxArgIdx  = 6,
    kScorDynArgIdx     = 7,
    kScorValTypeArgIdx = 8,
    kScorValueArgIdx   = 9,
    kScorMeasArgIdx    = 10,
    kScorVarCnt        = 11,
   
    kTksbFileArgIdx    = 0,
    kTksbPtrArgIdx     = 1,
    kTksbSelArgIdx     = 2,
    kTksbRefreshArgIdx = 3,
    kTksbVarCnt        = 4,

    kTksrPtrArgIdx     = 0,
    kTksrRefreshArgIdx = 1,
    kTksrSelArgIdx     = 2,
    kTksrVarCnt        = 3,

    kTwodXArgIdx       = 0,
    kTwodYArgIdx       = 1,
    kTwodRadiusArgIdx  = 2,
    kTwodAngleArgIdx   = 3,
    kTwodVarCnt        = 4

  }; 

  enum
  {
    kEnableBtnId = 1,
    kAudDevRptBtnId,
    kAudioSysCfgBtnId,
    kInAudDevBtnId,
    kOutAudDevBtnId,
    kPgmBtnId,
    kSubSystemIdxBtnId,
    kSrateBtnId,
    kTestBtnId,
    kPrintPgmBtnId,
    
    kAboutMenuId,
    kQuitMenuId
  };

  enum
  {
    k44100SrateIdx,
    k48000SrateIdx,
    k96000SrateIdx
  };

  typedef struct sldr_str
  {
    union
    {
      Fl_Value_Slider*  sldr;
      Fl_Value_Input*   numb;
    } u;
    Fl_Valuator*      val;
    double            defaultVal;
    unsigned          varIdArray[ kSldrVarCnt ];
  } sldr_t;

  typedef struct text_str
  {
    Fl_Input* text;
    char*      val;
    unsigned   varIdArray[ kTextVarCnt ];
  } text_t;

  typedef struct butn_str
  {
    Fl_Button* butn;
    double     val;
    unsigned   varIdArray[ kButnVarCnt ];
  } butn_t;

  typedef struct chck_str
  {
    Fl_Check_Button* chck;
    double           val;
    unsigned         varIdArray[ kChckVarCnt ];
  } chck_t;

  typedef struct labl_str
  {
    Fl_Box* box;
    unsigned varIdArray[ kLablVarCnt ];
  } labl_t;

  typedef struct fname_str
  {
    Fl_File_Btn* fnam;
    unsigned     varIdArray[ kFnamVarCnt ];
  } fnam_t;

  typedef struct mlst_str
  {
    Fl_Select_Browser* mlst;
    Fl_Menu_Button*    mbtn;
    int                sel;
    unsigned           varIdArray[ kMlstVarCnt ];
  } mlst_t;

  typedef struct metr_str
  {
    Fl_Progress* prog;
    unsigned     varIdArray[ kMetrVarCnt ];
  } metr_t;

  typedef struct tmln_str
  {
    tlCtl*     tlctl;
    char*      val;
    unsigned   varIdArray[ kTmlnVarCnt ];
  } tmln_t;

  typedef struct scor_str
  {
    tlCtl*     tlctl;
    unsigned   smpIdx;
    unsigned   pitch;
    unsigned   vel;
    unsigned   evtIdx;
    unsigned   locIdx;
    unsigned   varId;
    unsigned   varIdArray[ kScorVarCnt ];
  } scor_t;

  typedef struct tksb_str
  {
    tlCtl*     tlctl;
    unsigned   varIdArray[ kTksbVarCnt ];
  } tksb_t;

  typedef struct tksr_str
  {
    tlCtl*     tlctl;
    unsigned   varIdArray[ kTksrVarCnt ];
  } tksr_t;

  typedef struct twod_str
  {
    tlCtl* tlctl;
    unsigned varIdArray[ kTwodVarCnt ];
  } twod_t;


  typedef struct ctl_str
  {
    kcApp*     thisPtr;
    unsigned   asSubIdx;
    unsigned   typeId;
    unsigned   instId;
    Fl_Widget* wdgtPtr;
    bool       mstrFl;
    union
    {
      sldr_t     sldr;
      text_t     text;
      butn_t     butn;
      chck_t     chck;
      labl_t     labl;
      fnam_t     fnam;
      mlst_t     mlst;
      metr_t     metr;
      tmln_t     tmln;
      scor_t     scor;
      tksb_t     tksb;
      tksr_t     tksr;
      twod_t     twod;
    } u;
    struct ctl_str* linkPtr;
  } ctl_t;

  typedef struct page_str
  {
    Fl_Group* grp;
    struct page_str* link;
    page_str() : grp(NULL), link(NULL) {}
  } page_t;

  enum
  {
    kUpdateSsIdx,
    kWakeupSsIdx,
    kMsgSsIdx,
    kAudioCbSsIdx,
    kProgSsCnt
  };

  // each audio sub-system is represented by an ss_t record in _ssArray[_ssCnt]
  typedef struct ss_str
  {
    Fl_Progress* prog[kProgSsCnt]; // status indicator controls
    unsigned     cnt[kProgSsCnt];  // previous status count value
    
  } ss_t;

  cmCtx_t*         _ctx;
  cmPrH_t          _prH;
  cmAiH_t          _aiH;

  Fl_Menu_Bar*     _menu;
  Fl_Text_Display* _con;
  Fl_Tabs*         _tabs;
  Fl_Group*        _mstr_grp;

  Fl_Menu_Button*  _as_btn;
  Fl_Menu_Button*  _ai_btn;
  Fl_Menu_Button*  _ao_btn;
  Fl_Menu_Button*  _pgm_btn;
  Fl_Menu_Button*  _ss_btn;
  Fl_Menu_Button*  _sr_btn;
  Fl_Check_Button* _ena_chk;

  page_t*         _pageList;
  ctl_t*          _ctlList;
  bool            _stopTimerFl;
  bool            _newPageFl;
  unsigned        _incrColW;
  unsigned        _colW;
  bool            _horzBordFl;
  unsigned        _horzBord;
  unsigned        _ssCnt;   // count of audio system sub-systems (set in _handleSsInitMsg())
  ss_t*           _ssArray;
  int             _ssPhase;
  bool            _ssUpdateFl; 
  cmTsMp1cH_t     _printqH; // thread-safe queue for controlling access to the output console from multiple threads
  int             _printFl;
  tlCtl*          _tlCtl;

  void          _createSetupDlg(Fl_Group* grp);
  void          _createMenu( int w, int h );
  page_t*       _createPage( const char* title );

  unsigned      _getCtlCount() const;
  void          _clearCtlList(bool mstrFl);
  void          _clearSsArray();
  void          _getNewCtlPosn( const cmDspUiHdr_t* m, int& x, int& y, int& w, int& h );
  ctl_t*        _findCtl( unsigned instId, unsigned asSubIdx, unsigned mstrFl=false );
  ctl_t*        _createCtl( const cmDspUiHdr_t* m, unsigned typeId, int& x, int& y, int& w, int& h, bool posnFl=true );
  void          _insertNewCtl( ctl_t* cp, const cmDspUiHdr_t* m, Fl_Widget* wdgt, unsigned* varIdArray, unsigned varIdCnt );

  void          _createSlider(  const cmDspUiHdr_t* m );
  void          _setSldrValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createText(  const cmDspUiHdr_t* m );
  void          _setTextValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createFnameCtl(   const cmDspUiHdr_t* m );
  void          _setFnamValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createMlistCtl(   const cmDspUiHdr_t* m );
  kcKmRC_t      _loadMlist( ctl_t* cp, const cmJsonNode_t* np );
  void          _setMlistValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createMeter( const cmDspUiHdr_t* m );
  void          _setMeterValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createButton( const cmDspUiHdr_t* m );
  void          _setButtonValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createCheck( const cmDspUiHdr_t* m );
  void          _setCheckValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createLabel( const cmDspUiHdr_t* m );
  void          _setLabelValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createTmln(  const cmDspUiHdr_t* m );
  void          _setTmlnValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createScor(  const cmDspUiHdr_t* m );
  void          _setScorValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createTksb(  const cmDspUiHdr_t* m );
  void          _setTksbValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createTksr(  const cmDspUiHdr_t* m );
  void          _setTksrValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );
  void          _createTwod(  const cmDspUiHdr_t* m );
  void          _setTwodValue( ctl_t* cp, unsigned instVarId, const cmDspValue_t* vp );


  void          _newColumn( const cmDspUiHdr_t* m );

  void          _insertAudioSysCfgLabel(unsigned long idx, const cmChar_t* label );
  void          _setDfltAudioSysCfg(unsigned long idx, const cmChar_t* label );
  void          _insertDeviceLabel( unsigned long idx, bool inputFl, const cmChar_t* label );
  void          _insertProgramLabel( unsigned long idx, const cmChar_t* label );
  void          _setDfltProgram(unsigned long idx, const cmChar_t* label );
  void          _insertSubSysCnt( unsigned long subSysCnt );
  unsigned      _getCurAudioSubSysIdx();
  void          _setMenuButton( Fl_Menu_Button* b, unsigned value, const char* dfltLabel );
  void          _setDeviceMenuButton( unsigned asSubIdx, bool inputFl, unsigned devIdx );
  void          _setSampleRateBtn( unsigned value );

  void          _updateMeters( unsigned asSubIdx, unsigned devIdx, unsigned inFl, const double* meterArray, unsigned meterCnt );
  void          _updateSsStatusIndicator( unsigned asSubIdx, unsigned indicatorIdx, unsigned cnt );
  void          _printStatusCounts();
  void          _clearStatusIndicators();

  void          _sendMasterUiMsg(  unsigned asSubIdx, unsigned selId, unsigned instId, unsigned instVarId, const cmDspValue_t* v );
  void          _sendMasterUiValue(unsigned asSubIdx, unsigned instId, const double* v, unsigned vn, const cmChar_t* text );
  void          _createMasterCtl(  unsigned asSubIdx, unsigned selId, unsigned instId, unsigned varCnt, const double* dv, unsigned dn, const cmChar_t* label);
  
  void          _onRecvValue( const cmDspUiHdr_t* m );
  void          _getEngMsg();

 public:
   void          _handleStatusMsg( const cmAudioSysStatus_t* st, const double* iMeterArray, const double* oMeterArray );
   void          _handleSsInitMsg(  const cmAudioSysSsInitMsg_t* m, const cmChar_t* inDevLabel, const cmChar_t* outDevLabel );
   void          _handleUiMsg( const cmDspUiHdr_t* m );

 private:

  static kcApp* _getApp( Fl_Widget* w );
  void          _onCloseApp();
  
  void          _testStub();
  void          _printPgm();

  // main app callback
  static void _s_callback(Fl_Widget* wp, void* data);
  void _callback(void* data);

  // timer callback
  static void _s_status_timeout_cb(void* userPtr);
  bool _status_timeout_cb();

  static void _s_menu_cb(Fl_Widget *w, void *data); 

  static void _s_btn_cb(Fl_Widget* w, long data);
  void _btn_cb(Fl_Widget* w,  long arg);

  static void _s_ctl_cb(Fl_Widget* w, void* data);
  void _ctl_cb(ctl_t* cp);

  static void _s_tab_cb(Fl_Widget* w, void* data);
  void _tab_cb(Fl_Widget* w);

  // 
  static void _s_print( void* userPtr, const char* text );

  // called internally by cmTsQueueDequeue() to send text to _print()
  static cmRC_t _s_print_queue_cb(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr );

  // called periodically to check the print queue for waiting text.
  void        _checkPrintQueue();

  // send a string of text directly to the output console window
  void        _print( const char* text );


};



#endif
