// SyntaxView.cpp : Implementierung der Klasse CSyntaxView
//

#include "stdafx.h"
#include "SyntaxHtml.h"

#include "SyntaxDocument.h"
#include "SyntaxView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSyntaxView

IMPLEMENT_DYNCREATE(CSyntaxView, CFormView)

BEGIN_MESSAGE_MAP(CSyntaxView, CFormView)
   //{{AFX_MSG_MAP(CSyntaxView)
   ON_WM_DESTROY()
   ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
   ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdate_EditCopy)
   ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
   ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdate_EditPaste)
   ON_NOTIFY(NM_DBLCLK, IDC_ColorList, OnColorListDoubleClick)
   ON_BN_CLICKED(IDC_CheckConvertTabs, OnCheckConvertTabs)
   ON_COMMAND(ID_Update, OnUpdateCommand)
   ON_UPDATE_COMMAND_UI(ID_Update, OnUpdate_UpdateCommand)
   ON_EN_CHANGE(IDC_Spaces, OnChangeSpaces)
   ON_WM_CREATE()
   ON_UPDATE_COMMAND_UI(ID_PasteAppend, OnUpdate_PasteAppend)
   ON_CBN_SELENDOK(IDC_Fonts, OnFontSelected)
   ON_COMMAND(ID_ShowTitlePage, OnShowTitlePage)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSyntaxView Konstruktion/Destruktion

CSyntaxView::CSyntaxView()
   : CFormView(CSyntaxView::IDD)
{
   //{{AFX_DATA_INIT(CSyntaxView)
   m_nSpaces = 3;
   m_bConvertTabs = TRUE;
   m_nFont = -1;
   //}}AFX_DATA_INIT
   // ZU ERLEDIGEN: Hier Code zur Konstruktion einfügen,
   m_bRegisteredDropTarget = false;
}

CSyntaxView::~CSyntaxView()
{
}

void CSyntaxView::DoDataExchange(CDataExchange* pDX)
{
   CFormView::DoDataExchange(pDX);
   //{{AFX_DATA_MAP(CSyntaxView)
   DDX_Control(pDX, ID_Update, m_cUpdate);
   DDX_Control(pDX, IDC_ColorList, m_cColorList);
   DDX_Control(pDX, IDC_WebBrowser, m_cHtml);
   DDX_Text(pDX, IDC_Spaces, m_nSpaces);
   DDV_MinMaxInt(pDX, m_nSpaces, 1, 12);
   DDX_Check(pDX, IDC_CheckConvertTabs, m_bConvertTabs);
   DDX_CBIndex(pDX, IDC_Fonts, m_nFont);
   //}}AFX_DATA_MAP
}

BOOL CSyntaxView::PreCreateWindow(CREATESTRUCT& cs)
{
   // ZU ERLEDIGEN: Ändern Sie hier die Fensterklasse oder das Erscheinungsbild, indem Sie
   //  CREATESTRUCT cs modifizieren.

   return CFormView::PreCreateWindow(cs);
}

void CSyntaxView::OnInitialUpdate()
{
   CFormView::OnInitialUpdate();
   
   if(!::IsWindow(m_cHtml.m_hWnd))
   {
      AfxMessageBox(_T("Fatal Error: Internet Explorer Control could not be created!"));
      ExitProcess(1);
   }

   if(GetDocument()->m_sCode.IsEmpty())
      ShowTitlePage();

   m_cColorList.DeleteColumn(0);
   m_cColorList.DeleteColumn(0);
   m_cColorList.InsertColumn(0, _T("Symbol"), LVCFMT_LEFT, 120);
   m_cColorList.InsertColumn(1, _T("Samples"), LVCFMT_LEFT, 200, 1);
   Update_ColorList();

   GetDocument()->m_nSpaces = m_nSpaces;
   GetDocument()->m_bConvertTabs = (m_bConvertTabs != FALSE);

   if(!m_bRegisteredDropTarget)
   {
      VERIFY(m_DropTarget.Register(this));
      m_bRegisteredDropTarget = true;
   }

   BuildFontList();

   GetParentFrame()->RecalcLayout();
   ResizeParentToFit();
}

/////////////////////////////////////////////////////////////////////////////
// CSyntaxView Diagnose

#ifdef _DEBUG
void CSyntaxView::AssertValid() const
{
   CFormView::AssertValid();
}

void CSyntaxView::Dump(CDumpContext& dc) const
{
   CFormView::Dump(dc);
}

CSyntaxDocument* CSyntaxView::GetDocument() // Die endgültige (nicht zur Fehlersuche kompilierte) Version ist Inline
{
   ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSyntaxDocument)));
   return (CSyntaxDocument*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSyntaxView Nachrichten-Handler

void CSyntaxView::OnDestroy() 
{
   m_DropTarget.Revoke();

   CFormView::OnDestroy();
}

DROPEFFECT CSyntaxView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
   return pDataObject->IsDataAvailable(CF_TEXT) ? DROPEFFECT_COPY : DROPEFFECT_NONE;
}

DROPEFFECT CSyntaxView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
   return pDataObject->IsDataAvailable(CF_TEXT) ? DROPEFFECT_COPY : DROPEFFECT_NONE;
}

BOOL CSyntaxView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) 
{
   if(pDataObject->IsDataAvailable(CF_TEXT))
   {
      HGLOBAL hGlobal = pDataObject->GetGlobalData(CF_TEXT);
      DWORD dwTextLength = ::GlobalSize(hGlobal);
      CMemFile MemFile((BYTE *)::GlobalLock(hGlobal), dwTextLength);

      LPTSTR szCode = GetDocument()->m_sCode.GetBufferSetLength(dwTextLength);
      MemFile.Read(szCode, dwTextLength);
      ::GlobalUnlock(hGlobal);

//      TRACE("OLE Drop: text received = '%s'\r\n", szCode);

      GetDocument()->GenerateHtml(); // calls UpdateAllViews
      return TRUE;
   }

   return CFormView::OnDrop(pDataObject, dropEffect, point);
}

void CSyntaxView::OnDragLeave() 
{
   //$$ perhaps do something with this later on
   CFormView::OnDragLeave();
}

void CSyntaxView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
   switch(lHint)
   {
      case HINT_Html_Changed:
         Update_Html();
         break;
      
      default:
         break;
   }
}

void CSyntaxView::Update_Html()
{
   CString sFile;
   sFile.Format(_T("file:///%s"), GetDocument()->m_sHtmlFile);
   m_cHtml.Navigate(sFile, NULL, NULL, NULL, NULL);
}

void CSyntaxView::OnEditCopy() 
{
   COleDataSource *pSource = new COleDataSource();
   CSharedFile   SharedFile(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
   SharedFile.Write(GetDocument()->m_sHtml, GetDocument()->m_sHtml.GetLength());

   HGLOBAL hGlobal = SharedFile.Detach();
   if(!hGlobal)
      return;

   pSource->CacheGlobalData(CF_TEXT, hGlobal);
   pSource->SetClipboard();
}

void CSyntaxView::OnUpdate_EditCopy(CCmdUI* pCmdUI) 
{
   pCmdUI->Enable(!GetDocument()->m_sHtml.IsEmpty());
}

void CSyntaxView::OnEditPaste() 
{
   COleDataObject DataObject;

   if(DataObject.AttachClipboard()
   && DataObject.IsDataAvailable(CF_TEXT))
   {
      HGLOBAL hGlobal = DataObject.GetGlobalData(CF_TEXT);
      DWORD dwTextLength = ::GlobalSize(hGlobal);
      CMemFile MemFile((BYTE *)::GlobalLock(hGlobal), dwTextLength);

      LPTSTR szCode = GetDocument()->m_sCode.GetBufferSetLength(dwTextLength);
      MemFile.Read(szCode, dwTextLength);
      ::GlobalUnlock(hGlobal);

//      TRACE("OLE Paste: text received = '%s'\r\n", szCode);

      GetDocument()->GenerateHtml(); // calls UpdateAllViews
   }
}

void CSyntaxView::OnUpdate_EditPaste(CCmdUI* pCmdUI) 
{
   pCmdUI->Enable(IsClipboardFormatAvailable(CF_TEXT));
}

void CSyntaxView::Update_ColorList()
{
   CKeywords &Keywords = GetDocument()->m_Keywords;

   m_cColorList.SetRedraw(false);
   m_cColorList.DeleteAllItems();

   LV_ITEM ListItem;
   ZeroItem(ListItem);

   for( ; ListItem.iItem < MAX_Types; ListItem.iItem++)
   {
      ListItem.iSubItem = 0;
      ListItem.mask = LVIF_PARAM | LVIF_TEXT;
      ListItem.pszText = (LPTSTR)Keywords.m_aTypeStrings[ListItem.iItem];
      ListItem.lParam = (LPARAM)&Keywords.m_aTypeColors[ListItem.iItem];
      m_cColorList.InsertItem(&ListItem);

      ListItem.iSubItem = 1;
      ListItem.mask = LVIF_TEXT;
      ListItem.pszText = (LPTSTR)Keywords.m_aTypeSamples[ListItem.iItem];
      m_cColorList.SetItem(&ListItem);
   }

   m_cColorList.SetRedraw(true);
   m_cColorList.UpdateWindow();
}

LRESULT CSyntaxView::DoCustomDraw(NMCUSTOMDRAW *pCustomDraw)
{
   if(pCustomDraw->hdr.idFrom == IDC_ColorList
   && pCustomDraw->hdr.hwndFrom == m_cColorList.GetSafeHwnd())
   {
      if(pCustomDraw->dwDrawStage == CDDS_PREPAINT)
         return CDRF_NOTIFYITEMDRAW;

      if(pCustomDraw->dwDrawStage == CDDS_ITEMPREPAINT)
      {
         COLORREF rgbItem = *((COLORREF *)pCustomDraw->lItemlParam);
         // mojo hack mode: listctrl does not display sub items in
         // blue color, therefore just tweak the color a little bit...
         if(rgbItem == RGB(0, 0, 0xff))
            rgbItem++;
         
         ((NMLVCUSTOMDRAW *)pCustomDraw)->clrText = rgbItem;
      }
   }

   return CDRF_DODEFAULT;
}

BOOL CSyntaxView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
   NMHDR *pNMHDR = (NMHDR *)lParam;
   
   if(pNMHDR->code == NM_CUSTOMDRAW)
   {
      *pResult = DoCustomDraw((NMCUSTOMDRAW *)pNMHDR);
      return TRUE;
   }

   return CFormView::OnNotify(wParam, lParam, pResult);
}

void CSyntaxView::OnColorListDoubleClick(NMHDR* pNMHDR, LRESULT* pResult) 
{
   int iSelected = m_cColorList.GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED);

   if(iSelected > -1)
   {
      COLORREF *pColor = (COLORREF *)m_cColorList.GetItemData(iSelected);
      ASSERT(pColor && AfxIsValidAddress(pColor, sizeof(COLORREF)));

      CColorDialog Dialog;
      Dialog.m_cc.Flags |= CC_RGBINIT;
      Dialog.m_cc.rgbResult = *pColor;

      if(Dialog.DoModal() == IDOK)
      {
         *pColor = Dialog.GetColor();
         m_cColorList.Invalidate();
      }
   }

   *pResult = 0;
}

void CSyntaxView::OnCheckConvertTabs() 
{
   UpdateData();
   GetDocument()->m_bConvertTabs = (m_bConvertTabs != FALSE);
   GetDlgItem(IDC_Spaces)->EnableWindow(m_bConvertTabs != FALSE);
}

void CSyntaxView::OnUpdateCommand() 
{
   GetDocument()->GenerateHtml();
}

void CSyntaxView::OnUpdate_UpdateCommand(CCmdUI* pCmdUI) 
{
   bool bEnable = !GetDocument()->m_sCode.IsEmpty();
   pCmdUI->Enable(bEnable);
   m_cUpdate.EnableWindow(bEnable);
}

void CSyntaxView::OnChangeSpaces() 
{
   UpdateData(); /* hello!!! */
   GetDocument()->m_nSpaces = m_nSpaces;
}

int CSyntaxView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
   if(CFormView::OnCreate(lpCreateStruct) == -1)
      return -1;

   return 0;
}

//DEL void CSyntaxView::OnPasteAppend() 
//DEL {
//DEL    COleDataObject DataObject;
//DEL    CSyntaxDocument *pDocument = GetDocument();
//DEL 
//DEL    if(DataObject.AttachClipboard()
//DEL    && DataObject.IsDataAvailable(CF_TEXT))
//DEL    {
//DEL       HGLOBAL hGlobal = DataObject.GetGlobalData(CF_TEXT);
//DEL       DWORD dwTextLength = ::GlobalSize(hGlobal);
//DEL       CMemFile MemFile((BYTE *)::GlobalLock(hGlobal), dwTextLength);
//DEL       CString sAppend;
//DEL 
//DEL       LPTSTR szAppend = sAppend.GetBufferSetLength(dwTextLength);
//DEL       MemFile.Read(szAppend, dwTextLength);
//DEL       ::GlobalUnlock(hGlobal);
//DEL 
//DEL       pDocument->m_sCode += szAppend;
//DEL       pDocument->GenerateHtml(); // calls UpdateAllViews
//DEL    }
//DEL }

void CSyntaxView::OnUpdate_PasteAppend(CCmdUI* pCmdUI) 
{
   pCmdUI->Enable(IsClipboardFormatAvailable(CF_TEXT));
}

int CALLBACK Callback_EnumFontFamilies(
   ENUMLOGFONTEX *pEnumLogFont,      // pointer to logical-font data
   NEWTEXTMETRICEX *pNewTextMetric,   // pointer to physical-font data
   int nFontType,                     // type of font
   LPARAM lParam                     // application-defined data
)
{
   static CString s_sPreviousFace;
   
   if(s_sPreviousFace != pEnumLogFont->elfLogFont.lfFaceName)
   {
      CComboBox *pCombo = (CComboBox *)lParam;
      pCombo->AddString(pEnumLogFont->elfLogFont.lfFaceName);
   }
   
   s_sPreviousFace = pEnumLogFont->elfLogFont.lfFaceName;

   return 1;
}

void CSyntaxView::BuildFontList()
{
   CComboBox *pCombo = (CComboBox *)GetDlgItem(IDC_Fonts);
   ASSERT(pCombo);

   pCombo->ResetContent();

   LOGFONT LogFont;
   ZeroItem(LogFont);
   LogFont.lfCharSet = DEFAULT_CHARSET;

   EnumFontFamiliesEx(
      GetDC()->GetSafeHdc(),
      &LogFont,
      (FONTENUMPROC)Callback_EnumFontFamilies,
      (LPARAM)pCombo,
      0);

   int iDefaultFont = pCombo->FindString(-1, GetDocument()->m_sFontFace);
   if(iDefaultFont != CB_ERR)
      pCombo->SetCurSel(iDefaultFont);
}

void CSyntaxView::OnFontSelected() 
{
   CComboBox *pCombo = (CComboBox *)GetDlgItem(IDC_Fonts);
   int nSelection = pCombo->GetCurSel();
   if(nSelection > -1)
      pCombo->GetLBText(nSelection, GetDocument()->m_sFontFace);
}

void CSyntaxView::OnShowTitlePage() 
{
   ShowTitlePage();
}

void CSyntaxView::ShowTitlePage()
{
   static TCHAR s_szModule[MAX_PATH];
   GetModuleFileName(NULL, s_szModule, MAX_PATH);
   CString sModule;
   sModule.Format(_T("res://%s/HTML_ABOUT"), s_szModule);
   TRACE("%s\r\n", sModule);
   m_cHtml.Navigate(sModule, NULL, NULL, NULL, NULL);
}