//*****************************************
//******** PC Configurator V1.00 **********
//*** (C) - 2001 B.Bowling/A. Grippo ******
//** All derivatives from this software ***
//*** are required to keep this header ****
//*****************************************

static char *rcsId() { return "$Id$"; }

#include "stdafx.h"
#include "megatune.h"
#include "msDatabase.h"
#include "repository.h"
#include "megatuneDlg.h"
#include "Dabout.h"
#include "Dconstants.h"
#include "Druntime.h"
#include "Denrichments.h"
#include "Dvetable.h"
#include "Dsetcomm.h"
#include "Dttune.h"
#include "Dconplot.h"
#include "hexedit.h"
#include "tpgen.h"
#include "scaleVe.h"

#ifdef _DEBUG
#  define new DEBUG_NEW
#  undef THIS_FILE
   static char THIS_FILE[] = __FILE__;
#endif

extern msDatabase mdb;
extern repository rep;

//------------------------------------------------------------------------------
// CMegatuneDlg dialog

CMegatuneDlg::CMegatuneDlg(CWnd * pParent /*=NULL*/ )
 : CDialog(CMegatuneDlg::IDD, pParent)
{
   //{{AFX_DATA_INIT(CMegatuneDlg)
   //}}AFX_DATA_INIT
   // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::DoDataExchange(CDataExchange * pDX)
{
   CDialog::DoDataExchange(pDX);
   //{{AFX_DATA_MAP(CMegatuneDlg)
      DDX_Control(pDX, IDC_PAGE_NO_TEXT, m_pageNoText);
      DDX_Control(pDX, IDC_PAGE_NO, m_pageNo);
      DDX_Control(pDX, IDC_STATUS_LOGGING, m_statusLogging);
      DDX_Control(pDX, IDC_STATUS_FILENAME, m_statusFilename);
      DDX_Control(pDX, IDC_STATUS_SAVED, m_statusSaved);
      DDX_Control(pDX, IDC_STATUS_CONNECTED, m_statusConnected);
   //}}AFX_DATA_MAP
}

//------------------------------------------------------------------------------

BEGIN_MESSAGE_MAP(CMegatuneDlg, CDialog)
   //{{AFX_MSG_MAP(CMegatuneDlg)
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      ON_BN_CLICKED(IDC_CONSTANTS,   OnConstants)
      ON_BN_CLICKED(IDC_ENRICHMENTS, OnEnrichments)
      ON_BN_CLICKED(IDC_RUNTIME,     OnRuntime)
      ON_BN_CLICKED(IDC_VETABLE,     OnVetable)
      ON_BN_CLICKED(IDC_SETPORT,     OnSetport)
      ON_BN_CLICKED(IDC_TUNE,        OnTune)
      ON_COMMAND(ID_FILE_SAVE,       OnSave)
      ON_COMMAND(ID_FILE_SAVEAS,     OnSaveAs)
      ON_COMMAND(ID_FILE_DUMP,       OnDump)
      ON_COMMAND(ID_SETTINGS_CONTOURPLOT, OnContourPlot)
      ON_COMMAND(ID_HELP_ABOUT, OnAbout)
      ON_WM_TIMER()
      ON_COMMAND(ID_FILE_OPEN, OnOpen)
      ON_COMMAND(ID_DATALOG_C, OnDatalogC)
      ON_COMMAND(ID_DATALOG_F, OnDatalogF)
      ON_COMMAND(ID_DATALOG_R, OnDatalogR)
      ON_COMMAND(ID_DATALOG_X, OnDatalogX)
      ON_NOTIFY(UDN_DELTAPOS, IDC_PAGE_NO, OnDeltaPageNo)
      ON_COMMAND(ID_RUNTIME_HEXEDIT, OnHexedit)
      ON_COMMAND(ID_COMMLOG, OnCommlog)
      ON_COMMAND(ID_RUNTIME_TABLEEDIT, OnTableedit)
      ON_COMMAND(ID_FILE_VEEXPORT, OnVeExport)
      ON_COMMAND(ID_FILE_VEIMPORT, OnVeImport)
      ON_MESSAGE(WM_HOTKEY, OnHotKey)
      ON_WM_DESTROY()
      ON_COMMAND(ID_TOOLS_GENTP, OnGenerateTP)
      ON_COMMAND(ID_COMMUNICATIONS_SETTINGS, OnSetport)
      ON_COMMAND(ID_RUNTIME_REALTIMEDISPLAY, OnRuntime)
      ON_COMMAND(ID_RUNTIME_TUNING, OnTune)
      ON_COMMAND(ID_SETTINGS_CONSTANTS, OnConstants)
      ON_COMMAND(ID_SETTINGS_ENRICHMENTS, OnEnrichments)
      ON_COMMAND(ID_SETTINGS_VETABLE, OnVetable)
	ON_COMMAND(ID_TOOLS_SCALE_VE, OnScaleVe)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//------------------------------------------------------------------------------
FILE *log = NULL;

#if 1
void logSize(CWnd *, char *) { }
#else
void logSize(CWnd *w, char *title)
{
   if (log == NULL) log = fopen("event.log", "w");
   CRect r;
   w->GetWindowRect(&r);
// ScreenToClient(&r);
   fprintf(log, "%-12s w %d h %d\n", title, r.right-r.left, r.bottom-r.top);
   fflush(log);
}
#endif

//------------------------------------------------------------------------------
// CMegatuneDlg message handlers

static UINT indicators[] = {
   ID_SEPARATOR,
   ID_INDICATOR_FILE,
   ID_INDICATOR_SAVED,
   ID_INDICATOR_CONNECTED
};

static void setColors(CBarMeter &m)
{
   m.SetColor(CBarMeter::meter_needle,    rep.g_ledColor);
   m.SetColor(CBarMeter::meter_gridalert, rep.g_ledAlertColor);
   m.SetColor(CBarMeter::meter_bground,   rep.g_backgroundColor);
}

static void setColors(CAnalogMeter &m)
{
   m.SetColor(meter_title,     rep.g_titleColor);
   m.SetColor(meter_needle,    rep.g_needleColor);
   m.SetColor(meter_grid,      rep.g_scaleColor);
   m.SetColor(meter_gridalert, rep.g_alertColor);
   m.SetColor(meter_value,     rep.g_valueColor);
   m.SetColor(meter_range,     rep.g_rangeColor);
   m.SetColor(meter_bground,   rep.g_backgroundColor);
}

BOOL CMegatuneDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   logSize(this, "megatuneDlg");
#if 0
   if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) {
      TRACE0("Failed to create status bar\n");
      return -1;      // fail to create
   }

   if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
       !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
      TRACE0("Failed to create toolbar\n");
      return -1;      // fail to create
   }
#endif

   m_IDalt1HotKey = GlobalAddAtom("mtAlt1");
   RegisterHotKey(m_hWnd, m_IDalt1HotKey, MOD_ALT, '1');
   m_IDalt2HotKey = GlobalAddAtom("mtAlt2");
   RegisterHotKey(m_hWnd, m_IDalt2HotKey, MOD_ALT, '2');
   //m_IDaltRHotKey = GlobalAddAtom("mtAltR");
   //RegisterHotKey(m_hWnd, m_IDaltRHotKey, MOD_ALT, 'R');
   m_IDaltSHotKey = GlobalAddAtom("mtAltS");
   RegisterHotKey(m_hWnd, m_IDaltSHotKey, MOD_ALT, 'S');
   m_IDaltEHotKey = GlobalAddAtom("mtAltE");
   RegisterHotKey(m_hWnd, m_IDaltEHotKey, MOD_ALT, 'E');
   m_IDaltVHotKey = GlobalAddAtom("mtAltV");
   RegisterHotKey(m_hWnd, m_IDaltVHotKey, MOD_ALT, 'V');
   m_IDctlSHotKey = GlobalAddAtom("mtCtlS");
   RegisterHotKey(m_hWnd, m_IDctlSHotKey, MOD_CONTROL, 'S');

   // Set the icon for this dialog.  The framework does this automatically
   // when the application's main window is not a dialog.
   SetIcon(m_hIcon, TRUE);       // Set big icon
   SetIcon(m_hIcon, FALSE);      // Set small icon

   mdb.Create(msDatabase::IDD, this);

   meterRPM.SetRange(rep.lofRPM, rep.hifRPM);
   meterRPM.SetAlert(rep.rdfRPM > 0.0 ? rep.rdfRPM : rep.hifRPM);
   meterRPM.SetTitle("Engine Speed");
   meterRPM.SetUnit ("RPM");
   meterRPM.SetValueDecimals(0);
   meterRPM.SetRangeDecimals(0);
   setColors(meterRPM);

   meterTP.SetRange(rep.lofTP, rep.hifTP);
   meterTP.SetAlert(rep.rdfTP > 0.0 ? rep.rdfTP : rep.hifTP);
   meterTP.SetTitle("Throttle Position");
   meterTP.SetUnit("%");
   meterTP.SetValueDecimals(0);
   meterTP.SetRangeDecimals(0);
   setColors(meterTP);

   meterPW1.SetRange(rep.lofPW, rep.hifPW);
   meterPW1.SetAlert(rep.rdfPW > 0.0 ? rep.rdfPW : rep.hifPW);
   meterPW1.SetTitle("Pulse Width 1");
   meterPW1.SetUnit ("mSec");
   setColors(meterPW1);

   meterDC1.SetRange(rep.lofDC, rep.hifDC);
   meterDC1.SetAlert(rep.rdfDC > 0.0 ? rep.rdfDC : rep.hifDC);
   meterDC1.SetTitle("Duty Cycle 1");
   meterDC1.SetUnit ("%");
   setColors(meterDC1);

   meterMAP.SetRange(rep.lofMAP, rep.hifMAP);
   meterMAP.SetAlert(rep.rdfMAP > 0.0 ? rep.rdfMAP : rep.hifMAP);
   meterMAP.SetTitle("Engine MAP");
   meterMAP.SetUnit("kPa");
   meterMAP.SetValueDecimals(0);
   meterMAP.SetRangeDecimals(0);
   setColors(meterMAP);

   meterMAT.SetRange(rep.lofMAT, rep.hifMAT);
   meterMAT.SetAlert(rep.rdfMAT > 0.0 ? rep.rdfMAT : rep.hifMAT);
   meterMAT.SetTitle("Manifold Air Temp");
   char matLabel[20];
   sprintf(matLabel, "° %c", mdb.therm == msDatabase::Fahrenheit ? 'F' : 'C');
   meterMAT.SetUnit(matLabel);
   meterMAT.SetValueDecimals(0);
   meterMAT.SetRangeDecimals(0);
   setColors(meterMAT);

   meterPW2.SetRange(rep.lofPW, rep.hifPW);
   meterPW2.SetAlert(rep.rdfPW > 0.0 ? rep.rdfPW : rep.hifPW);
   meterPW2.SetTitle("Pulse Width 2");
   meterPW2.SetUnit ("mSec");
   setColors(meterPW2);

   meterDC2.SetRange(rep.lofDC, rep.hifDC);
   meterDC2.SetAlert(rep.rdfDC > 0.0 ? rep.rdfDC : rep.hifDC);
   meterDC2.SetTitle("Duty Cycle 2");
   meterDC2.SetUnit ("%");
   setColors(meterDC2);

   meterEGO.SetRange(rep.lotEGO, rep.hitEGO);
   meterEGO.SetAlert(rep.rdtEGO > 0.0 ? rep.rdtEGO : mdb.Const(Degoswitchv)/255.0*5.0);
   setColors(meterEGO);

   m_statusConnected.SetWindowText("CONNECTED");
   m_statusConnected.EnableWindow(false);
   m_statusSaved.SetWindowText("SAVED");
   m_statusSaved.EnableWindow(false);
   m_statusLogging.SetWindowText("LOGGING");
   m_statusLogging.EnableWindow(false);
   m_statusFilename.SetWindowText(*mdb.settingsFile ? mdb.settingsFile : "No file loaded");
   timer(on);

   return TRUE;
}

//------------------------------------------------------------------------------

LRESULT CMegatuneDlg::OnHotKey(WPARAM wp, LPARAM)
{
   if (wp == m_IDalt1HotKey) SetPage(0);
   if (wp == m_IDalt2HotKey) SetPage(1);
   //if (wp == m_IDaltRHotKey) OnRuntime();
   if (wp == m_IDaltSHotKey) OnConstants();
   if (wp == m_IDaltEHotKey) OnEnrichments();
   if (wp == m_IDaltVHotKey) OnVetable();
   if (wp == m_IDctlSHotKey) OnSave();
   return 0;
}

//------------------------------------------------------------------------------
// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMegatuneDlg::OnPaint()
{
   CPaintDC dc(this);
   if (IsIconic()) {
      SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);

      // Center icon in client rectangle
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);

      CRect          rect;
      GetClientRect(&rect);
      int x = (rect.Width () - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;

      // Draw the icon
      dc.DrawIcon(x, y, m_hIcon);
   }
   else {
      CDialog::OnPaint();
      CRect r;

      GetDlgItem(IDC_FRAME_1)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterRPM.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_2)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterTP.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_3)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterPW1.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_4)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterDC1.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_5)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterMAP.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_6)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterMAT.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_7)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterPW2.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_8)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterDC2.ShowMeter(&dc, r);

      GetDlgItem(IDC_FRAME_BAR)->GetWindowRect(&r);
      ScreenToClient(&r);
      meterEGO.ShowMeter(&dc, r);
   }
}

//------------------------------------------------------------------------------

void CMegatuneDlg::timer(int state)
{
   if (state == on) {
      if (SetTimer(1, mdb.timerInterval, NULL) == 0)
         MessageBox("ERROR: Cannot install timer.\nKill other useless Windows Apps.");
   }
   else {
      KillTimer(1);
      Sleep(mdb.timerInterval);
   }
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnTimer(UINT nIDEvent)
{
   static bool firstRead = true;
   unsigned char rtv[Rget];
   if (!mdb.getRuntime(rtv)) {
      m_statusConnected.SetWindowText("CONNECTED");
      m_statusConnected.EnableWindow(false);
   }
   else {
      if (firstRead) {
         mdb.getConst();
         firstRead = false;
      }

      if (mdb.controllerReset) {
         char msg[20];
         sprintf(msg, "RESET %d", mdb.controllerResetCount);
         m_statusConnected.SetWindowText(msg);
      }

      m_statusConnected.EnableWindow(true);

      CDC *dc = GetDC();

      meterRPM.UpdateNeedle(dc, rtv[Rrpm]*100.0);
      meterTP .UpdateNeedle(dc, mdb.throttle);
      meterPW1.UpdateNeedle(dc, mdb.pulseWidth1);
      meterDC1.UpdateNeedle(dc, mdb.dutyCycle1);

      meterMAP.UpdateNeedle(dc, mdb.map);
      meterMAT.UpdateNeedle(dc, mdb.mat);
      meterPW2.UpdateNeedle(dc, mdb.pulseWidth2);
      meterDC2.UpdateNeedle(dc, mdb.dutyCycle2);

      double EGO = rtv[Rego] * 0.0195312;
      meterEGO.UpdateNeedle(dc, EGO);

      ReleaseDC(dc);
   }

   m_pageNo.EnableWindow(mdb.dualTable());
   m_statusSaved.EnableWindow(!mdb.changed());

   CDialog::OnTimer(nIDEvent);
}

//------------------------------------------------------------------------------
// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.

HCURSOR CMegatuneDlg::OnQueryDragIcon()
{
   return (HCURSOR) m_hIcon;
}

void CMegatuneDlg::OnConstants()
{
   static bool inConst = false;
   if (!inConst) {
      inConst = true;
      timer(off);
      Dconstants xyz;
      xyz.DoModal();
      timer(on);
      inConst = false;
   }

}

void CMegatuneDlg::OnEnrichments()
{
   static bool inEnrich = false;
   if (!inEnrich) {
      inEnrich = true;
      timer(off);
      Denrichments xyz;
      xyz.DoModal();
      timer(on);
      inEnrich = false;
   }
}

void CMegatuneDlg::OnRuntime()
{
   static bool inRuntime = false;
   if (!inRuntime) {
      inRuntime = true;
      timer(off);
      Druntime xyz;
      xyz.DoModal();
      timer(on);
      inRuntime = false;
   }
}

void CMegatuneDlg::OnVetable()
{
   timer(off);
   Dvetable xyz;
   xyz.DoModal();
   timer(on);
}

void CMegatuneDlg::OnSetport()
{
   timer(off);
   Dsetcomm xyz;
   xyz.DoModal();
   timer(on);
}

void CMegatuneDlg::OnTune()
{
   timer(off);
   Dttune xyz;
   xyz.DoModal();
   timer(on);
}

void CMegatuneDlg::OnHexedit()
{
   if (mdb.dualTable()) {
      timer(off);
      hexedit xyz;
      xyz.DoModal();
      timer(on);
   }
}

void CMegatuneDlg::OnTableedit()
{
   timer(off);
   hexedit xyz(NULL, false);
   xyz.DoModal();
   timer(on);
}

//------------------------------------------------------------------------------

BOOL CMegatuneDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
#if 0
   if(log==NULL) log=fopen("event.log", "w");
   fprintf(log, "wParam = 0x%08x  lParam = 0x%08x\n", wParam, lParam);
   fflush(log);
#endif

   if (wParam == IDOK) return TRUE;

   if (wParam == IDCANCEL && mdb.changed()) {
      timer(off);
      int response = MessageBox("Save changes before quitting?", "Save", MB_YESNOCANCEL | MB_DEFBUTTON1 | MB_ICONQUESTION);
      switch (response) {
         case IDCANCEL:
            timer(on);
            return TRUE;
         case IDYES:
            OnSaveAs();
            break;
      }
   }

   return CDialog::OnCommand(wParam, lParam);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnSave()
{
   static bool inOnSave = false;
   if (!inOnSave) {
      inOnSave = true;
      timer(off);
      mdb.save();
      m_statusFilename.SetWindowText(mdb.settingsFile);
      timer(on);
      inOnSave = false;
   }
}

void CMegatuneDlg::OnSaveAs()
{
   timer(off);
   mdb.saveAs();
   m_statusFilename.SetWindowText(mdb.settingsFile);
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnOpen()
{
   timer(off);
   mdb.open();
   m_statusFilename.SetWindowText(mdb.settingsFile);
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnDatalogC()
{
   timer(off);
   mdb.setRecording(true);
   m_statusLogging.EnableWindow(mdb.recording());
   timer(on);
}

void CMegatuneDlg::OnDatalogF()
{
   timer(off);
   mdb.setRecording(true, msDatabase::fullLog);
   m_statusLogging.EnableWindow(mdb.recording());
   timer(on);
}

void CMegatuneDlg::OnDatalogR()
{
   timer(off);
   mdb.setRecording(true, msDatabase::rawLog);
   m_statusLogging.EnableWindow(mdb.recording());
   timer(on);
}

void CMegatuneDlg::OnDatalogX()
{
   timer(off);
   mdb.setRecording(false);
   m_statusLogging.EnableWindow(mdb.recording());
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnDump()
{
   timer(off);
   mdb.dump();
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnVeExport()
{
   timer(off);
   mdb.veExport();
   timer(on);
}

void CMegatuneDlg::OnVeImport()
{
   timer(off);
   mdb.veImport();
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnContourPlot()
{
   timer(off);
   Dconplot plot;
   plot.DoModal();
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnGenerateTP()
{
   timer(off);
   tpgen gen;
   gen.DoModal();
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnScaleVe()
{
   timer(off);
   scaleVe sve;
   sve.DoModal();
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnAbout()
{
   timer(off);
   Dabout about;
   about.DoModal();
   timer(on);
}

//------------------------------------------------------------------------------

void CMegatuneDlg::SetPage(int pageNo)
{
   pageNo = mdb.setPageNo(pageNo);
   char txt[10];
   sprintf(txt, "P%d", pageNo+1);
   m_pageNoText.SetWindowText(txt);
}

void CMegatuneDlg::OnDeltaPageNo(NMHDR* pNMHDR, LRESULT* pResult)
{
   NM_UPDOWN* pNMUpDown = reinterpret_cast<NM_UPDOWN *>(pNMHDR);
   SetPage(mdb.pageNo()-pNMUpDown->iDelta);
   *pResult = 0;
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnCommlog()
{
   bool state = mdb.toggleCommLogging();
   GetMenu()->CheckMenuItem(ID_COMMLOG, MF_BYCOMMAND | (state ? MF_CHECKED : MF_UNCHECKED));
}

//------------------------------------------------------------------------------

void CMegatuneDlg::OnDestroy()
{
   CDialog::OnDestroy();

   UnregisterHotKey(m_hWnd, m_IDalt1HotKey);
   UnregisterHotKey(m_hWnd, m_IDalt2HotKey);
   //UnregisterHotKey(m_hWnd, m_IDaltRHotKey);
   UnregisterHotKey(m_hWnd, m_IDaltSHotKey);
   UnregisterHotKey(m_hWnd, m_IDaltEHotKey);
   UnregisterHotKey(m_hWnd, m_IDaltVHotKey);
   UnregisterHotKey(m_hWnd, m_IDctlSHotKey);
}

//------------------------------------------------------------------------------

