#include "DemoIDEPch.h"
#include <stdio.h>
#include "TimelineWindow.h"


TimelineWindow::TimelineWindow()
{  
  m_DemoIDEView.m_iTicks        = 18000;
  m_DemoIDEView.m_iStartTick    = 0;
  m_DemoIDEView.m_iScale        = 100;
  m_DemoIDEView.m_iCurrentTick  = 0;  
  m_DemoIDEView.m_bBPM          = false;
  m_DemoIDEView.m_iBPM          = 100;
  m_DemoIDEView.m_iStartBPM     = 0;


  m_iStartLimit = 2000;
  m_iEndLimit   = 5000;
}


int TimelineWindow::Init(Window* pParent)
{
  if (Window::InitPrivate("Timeline", 0, WS_HSCROLL | WS_CHILDWINDOW, pParent) == -1)
  {
    return -1;
  }

  SetSize(640, 32);

  m_bIsOK = true;

  UpdateScrollBar(m_DemoIDEView.m_iStartTick);
  Show();    

  LOGFONT lf     = {-12,0,0,0,400,0,0,0,0,3,2,1,34,"Trebuchet MS"};  
  font           = CreateFontIndirect (&lf);
  hBrushWhite    = CreateSolidBrush(RGB(255, 255, 255));
  hBrushGreen    = CreateSolidBrush(RGB(0, 224, 0));
  hPenHalfGreen  = CreatePen(PS_SOLID, 0, RGB(0, 162, 0));
  hBrushPurple   = CreateSolidBrush(RGB(224, 0, 224));
  hPenHalfPurple = CreatePen(PS_SOLID, 0, RGB(162, 0, 162));
  hBrushRed    = CreateSolidBrush(RGB(100, 100, 224));
  hPenHalfRed  = CreatePen(PS_SOLID, 0, RGB(100, 100, 162));
  

  hStartLimit    = 0;
  hEndLimit      = 0;
  hBPM           = 0;
  
  return 0;
}

int TimelineWindow::Shutdown()
{
  if (m_bIsOK)
  {
    DeleteObject(font);
    DeleteObject(hBrushWhite);
    DeleteObject(hBrushGreen); 
    DeleteObject(hPenHalfGreen);
    DeleteObject(hBrushRed); 
    DeleteObject(hPenHalfRed);

    if (hStartLimit) { DeleteObject(hStartLimit); hStartLimit = 0; }
    if (hEndLimit)   { DeleteObject(hEndLimit); hEndLimit = 0; }
    if (hBPM)   { DeleteObject(hBPM); hBPM = 0; }    

    m_bIsOK = false;
  }

  return 0;
}

void TimelineWindow::SetBPMGuide(bool bGuide)
{
  m_DemoIDEView.m_bBPM = bGuide;
  UpdateScrollBar(m_DemoIDEView.m_iStartTick);
}

void TimelineWindow::SetLength(int iTicks)
{
  m_DemoIDEView.m_iTicks = iTicks;
  UpdateScrollBar(m_DemoIDEView.m_iStartTick);

  m_iStartLimit = min(iTicks, m_iStartLimit);
  m_iEndLimit   = min(iTicks, m_iEndLimit);  
}

void TimelineWindow::SetScale(int iScale)
{
  m_DemoIDEView.m_iScale = iScale;
  UpdateScrollBar(m_DemoIDEView.m_iStartTick);
}

BOOL CALLBACK TimelineWindow::BPMDlgProc( HWND _hdlg, UINT _uMsg, WPARAM _wparam, LPARAM _lparam)
{
  static BPMDlgProcData* pData = 0;
  switch (_uMsg)
  {
    case WM_INITDIALOG :
    {
      pData = (BPMDlgProcData*) _lparam;
      TimelineWindow* pWS = pData->m_pTimelineWindow;
      
  
      assert(pData);  
      //SetWindowPos(_hdlg,HWND_TOPMOST,0,0,1,1,SWP_NOMOVE|SWP_NOSIZE);

      // Iterate through effects
      char pcAux[100];
      sprintf(pcAux, "%i", pData->m_iBPM);
      Edit_SetText(GetDlgItem( _hdlg, IDC_BPMS), pcAux);

      RECT r;
      GetClientRect(_hdlg, &r);

      SetWindowPos(_hdlg,0,
          (GetSystemMetrics(SM_CXSCREEN)-r.right)/2,
          (GetSystemMetrics(SM_CYSCREEN)-r.bottom)/2,r.right,r.bottom, SWP_NOSIZE | SWP_NOOWNERZORDER);
      
      return TRUE;
    }        
    case WM_COMMAND :
      switch ( LOWORD(_wparam) )
      {
      case IDOK:
        {
          char pcAux[100];
          Edit_GetText(GetDlgItem( _hdlg, IDC_BPMS), pcAux, 100);
          pData->m_iBPM = atoi(pcAux);

          EndDialog( _hdlg, IDOK );
          break;
        }
      case IDCANCEL :
        EndDialog( _hdlg, IDCANCEL );
        break;
      }
      break;
  }

  return FALSE;
}

int TimelineWindow::ProcessMessage(const UINT message, const WPARAM wParam, const LPARAM lParam)
{
  static bool bDragStart = false;
  static bool bDragEnd   = false;

  static bool bDragBPM   = false;

  switch (message)
  {
  case WM_ERASEBKGND:
    return 0;
  
  case WM_PAINT:   
    {
      Paint();
    }
    break;

  case WM_LBUTTONDBLCLK:
  {
    int x = LOWORD(lParam);
    int y = HIWORD(lParam);

    if (hBPM && PtInRegion(hBPM, x, y))
    {
      BPMDlgProcData Data;
      Data.m_pTimelineWindow = this;
      Data.m_iBPM            = m_DemoIDEView.m_iBPM;

      if (DialogBoxParam(	
        SM_Main::HInstance(),
        MAKEINTRESOURCE(IDD_BPM),
        Hwnd(), 
        (DLGPROC)BPMDlgProc,
        (LPARAM) &Data) == IDOK)
      {
        m_DemoIDEView.m_iBPM = Data.m_iBPM;
        UpdateScrollBar(m_DemoIDEView.m_iStartTick);        
      }
    }
      break;
  }


  case WM_MOUSEMOVE:
    {
      if (!(wParam & MK_LBUTTON))
      {        
        bDragStart    = false;
        bDragEnd      = false;
        bDragBPM      = false;
        break;
      }

      if (bDragStart)
      {
        int x = LOWORD(lParam);
  
        m_iStartLimit = max(0, min(m_iEndLimit, min(m_DemoIDEView.m_iTicks, m_DemoIDEView.PixelToTick(x))));
        UpdateScrollBar(m_DemoIDEView.m_iStartTick);
        break;
      }

      if (bDragEnd)
      {
        int x = LOWORD(lParam);
  
        m_iEndLimit = max(0, max(m_iStartLimit, min(m_DemoIDEView.m_iTicks, m_DemoIDEView.PixelToTick(x))));
        UpdateScrollBar(m_DemoIDEView.m_iStartTick);
        break;
      }

      if (bDragBPM)
      {
        int x = LOWORD(lParam);
        m_DemoIDEView.m_iStartBPM = min(m_DemoIDEView.m_iTicks, m_DemoIDEView.PixelToTick(x));
        UpdateScrollBar(m_DemoIDEView.m_iStartTick);
      }           
    }
    // Fallthrough
  
  case WM_LBUTTONDOWN:
    {
    int x = LOWORD(lParam);
    int y = HIWORD(lParam);

    if (hStartLimit && PtInRegion(hStartLimit, x, y))
    {      
      bDragStart = true;
    }
    else if (hEndLimit && PtInRegion(hEndLimit, x, y))
    {
      bDragEnd = true;
    }
    else if (hBPM && PtInRegion(hBPM, x, y))
    {
      bDragBPM = true;
    }
    else if (!bDragStart && !bDragEnd && !bDragBPM)
    {    
      m_DemoIDEView.m_iCurrentTick = min(m_DemoIDEView.m_iTicks, m_DemoIDEView.PixelToTick(x));
    }
    
    TimesetEvent Event(&m_DemoIDEView);
    PostEvent(&Event);

    UpdateScrollBar(m_DemoIDEView.m_iStartTick);

    break;
    }

  case WM_LBUTTONUP:
    {
      bDragStart = false;
      bDragEnd   = false;
    break;
    }

  case WM_SIZE:
    {
      UpdateScrollBar(m_DemoIDEView.m_iStartTick);      
    }
    break;

  case WM_HSCROLL: 
    { 
      int iPos = m_DemoIDEView.m_iStartTick;
      bool bUpdate = true;
      switch (LOWORD(wParam)) 
      { 
        case SB_PAGELEFT: 
            iPos -= m_iPageSize; 
            break; 
        case SB_PAGERIGHT: 
            iPos += m_iPageSize; 
            break; 
        case SB_LINELEFT: 
            iPos -= m_DemoIDEView.m_iScale; 
            break; 
        case SB_LINERIGHT: 
            iPos += m_DemoIDEView.m_iScale; 
            break; 
        case SB_THUMBTRACK:                  
        case SB_THUMBPOSITION: 
            iPos = (HIWORD(wParam)/m_DemoIDEView.m_iScale)*m_DemoIDEView.m_iScale;              
            assert(iPos % m_DemoIDEView.m_iScale == 0);
            break; 
        default:
          bUpdate = false;
          break;
      } 

      if (bUpdate)
      {
        UpdateScrollBar(iPos);
      }                      
    } 
  }
  return Window::ProcessMessage(message, wParam, lParam);
}

void TimelineWindow::PaintBPMGuide(HDC hdc)
{
  if (!m_DemoIDEView.m_bBPM)
  {
    if (hBPM) 
    {
      DeleteObject(hBPM); hBPM = 0;
    }
    return;
  }
  
  PaintPointer(hdc, m_DemoIDEView.m_iStartBPM, hBrushRed, hPenHalfRed, &hBPM);  

  int w,h;
  GetClientSize(&w, &h);

  /*
  int i;
  int iTick; ;
  for (i = 0, iTick = m_DemoIDEView.m_iStartBPM  ; 
       i <= w && iTick <= m_DemoIDEView.m_iTicks ; 
       i += TICKWIDTH, iTick += m_DemoIDEView.m_iScale)
  {
  }
*/
}

void TimelineWindow::Paint()
{
  
  HDC hdcwindow;
  PAINTSTRUCT ps;

  hdcwindow = BeginPaint(m_hwnd, &ps);

  HDC hdc= CreateCompatibleDC(hdcwindow);

  int w,h;
  GetClientSize(&w, &h);

  
  HBITMAP hbitmap = CreateCompatibleBitmap(hdcwindow, w, h);
  HBITMAP holdbitmap = (HBITMAP) SelectObject(hdc, hbitmap);

  
  RECT rect;
  rect.left   = 0; rect.top    = 0; rect.bottom = h; rect.right  = w;
  FillRect(hdc, &rect, hBrushWhite);       
          
  int i;
  int iTick; ;
  for (i = 0, iTick = m_DemoIDEView.m_iStartTick  ; 
       i <= w && iTick <= m_DemoIDEView.m_iTicks ; 
       i += TICKWIDTH, iTick += m_DemoIDEView.m_iScale)
  {
    RECT rect;
    rect.left   = i; rect.top    = 0; rect.right  = i+1; rect.bottom = (iTick/m_DemoIDEView.m_iScale)%BIGTICK?4:16;
    FillRect(hdc, &rect, (HBRUSH) (COLOR_WINDOWTEXT+1));

    if ((iTick / m_DemoIDEView.m_iScale) % BIGTICK == 0)
    {
      char pcText[128];

      if (m_DemoIDEView.m_iScale < 10)
      {
        sprintf(pcText,"%i:%02i:%01i", (iTick/100)/60, (iTick/100)%60, (iTick%100)/10);
      }
      else
      {
        sprintf(pcText,"%i:%02i", (iTick/100)/60, (iTick/100)%60);
      }
      SelectObject (hdc, font) ;
      SetBkMode(hdc, TRANSPARENT);
      TextOut (hdc, i+2, 3, pcText, strlen(pcText)) ;
    }    
  }
  
  PaintLimits(hdc);
  PaintPointer(hdc, m_DemoIDEView.m_iCurrentTick, hBrushGreen, hPenHalfGreen);


  PaintBPMGuide(hdc);   

  BitBlt(hdcwindow, 0, 0, w, h, hdc, 0, 0, SRCCOPY);
  DeleteDC(hdc);
  DeleteObject(hbitmap);

  EndPaint(m_hwnd, &ps);             
}

void TimelineWindow::Update()
{
  UpdateScrollBar(m_DemoIDEView.m_iStartTick);
}
void TimelineWindow::UpdateScrollBar(int iStartTick)
{
  int w;
  GetClientSize(&w, 0);

  m_iPageSize = min(m_DemoIDEView.m_iTicks, m_DemoIDEView.m_iScale*(w/TICKWIDTH*TICKWIDTH)/(TICKWIDTH));

  // Set control bar
  SCROLLINFO si;
  si.cbSize = sizeof(SCROLLINFO);
  si.fMask  = SIF_RANGE;
  si.nMin   = 0;
  si.nMax   = m_DemoIDEView.m_iTicks-1;
  SetScrollInfo(m_hwnd, SB_HORZ, &si, TRUE);

  si.fMask  = SIF_PAGE;
  si.nPage  = m_iPageSize;
  SetScrollInfo(m_hwnd, SB_HORZ, &si, TRUE);

  iStartTick = min(m_DemoIDEView.m_iTicks-m_iPageSize, max(0, iStartTick));
  si.fMask  = SIF_POS; 
  si.nPos   = iStartTick;

  SetScrollInfo(m_hwnd, SB_HORZ, &si, TRUE); 

  m_DemoIDEView.m_iStartTick = iStartTick;

  InvalidateRect(m_hwnd, 0, TRUE);
  UpdateWindow(m_hwnd);

  // Send Event for update
  TimelineUpdateEvent Event(&m_DemoIDEView);
  
  PostEvent(&Event);
}

void TimelineWindow::PaintPointer(HDC hdc, int iTick, HBRUSH hBrush, HPEN hPenHalf, HRGN* pRGN)
{
  POINT arr[3];

  #define COMMANDWIDTH 10

  int x=m_DemoIDEView.TickToPixel(iTick);
  int y=0;
   
  arr[0].x = x                ; arr[0].y = y+COMMANDWIDTH;
  arr[1].x = x-COMMANDWIDTH/2 ; arr[1].y = y;  
  arr[2].x = x+COMMANDWIDTH/2 ; arr[2].y = y;
  
  int iPoints = 3;

  HGDIOBJ hPrevBrush = SelectObject(hdc, hBrush); 
  PolyPolygon(hdc, arr, &iPoints,  1);
  SelectObject(hdc, hPrevBrush); 

  HGDIOBJ hPrevPen = SelectObject(hdc, hPenHalf); 
  Polyline(hdc, arr, 2);
  SelectObject(hdc, hPrevPen);     

  if (pRGN)
  {
    if (*pRGN)
    {
      DeleteObject(*pRGN);
    }
    *pRGN = CreatePolygonRgn(arr, 3, ALTERNATE);
  }
}

void TimelineWindow::PaintLimits(HDC hdc)
{
  return;
  #define LIMITWIDTH 16

  POINT arr[3];


  int x,y, iPoints;
  HGDIOBJ hPrevBrush, hPrevPen;

  // Start Limit
  x=m_DemoIDEView.TickToPixel(m_iStartLimit);
  y=0;
   
  arr[0].x = x                ; arr[0].y = y;
  arr[1].x = x-LIMITWIDTH/2   ; arr[1].y = y+LIMITWIDTH/2;  
  arr[2].x = x                ; arr[2].y = y+LIMITWIDTH;
  
  iPoints = 3;

  hPrevBrush = SelectObject(hdc, hBrushPurple); 
  PolyPolygon(hdc, arr, &iPoints,  1);
  SelectObject(hdc, hPrevBrush); 

  hPrevPen = SelectObject(hdc, hPenHalfPurple); 
  Polyline(hdc, arr, 2);
  SelectObject(hdc, hPrevPen);     

  if (hStartLimit)
  {
    DeleteObject(hStartLimit);
  }

  hStartLimit = CreatePolygonRgn(arr, 3, ALTERNATE);
  

  // End Limit  
  x=m_DemoIDEView.TickToPixel(m_iEndLimit);
  y=0;
   
  arr[0].x = x                ; arr[0].y = y;
  arr[1].x = x+LIMITWIDTH/2   ; arr[1].y = y+LIMITWIDTH/2;  
  arr[2].x = x                ; arr[2].y = y+LIMITWIDTH;
  
  iPoints = 3;

  hPrevBrush = SelectObject(hdc, hBrushPurple); 
  PolyPolygon(hdc, arr, &iPoints,  1);
  SelectObject(hdc, hPrevBrush); 

  hPrevPen = SelectObject(hdc, hPenHalfPurple); 
  Polyline(hdc, arr, 2);
  SelectObject(hdc, hPrevPen);     

  if (hEndLimit)
  {
    DeleteObject(hEndLimit);
  }
  hEndLimit = CreatePolygonRgn(arr, 3, ALTERNATE);
}

