/******************************************************************************
** Copyright (C) 2001, University of Alabama in Huntsville. All rights 
** reserved.
**
** File   : ConGraTView.cpp
**
** Author : Satish Hota & Edwin Chan (with help from MFC)
**
** Description:
**    This file provides implementation for CConGraTView class.
**
** History:
** 09-Nov-01 Satish Hota & Edwin Chan
**     File Created
** 19-Nov-01 Edwin Chan
**     Added Message Handlers
** 24-Nov-01 Satish Hota
**     Tentatively modified OnInitialUpdate
** 25-Nov-01 Satish Hota
**     * Added new ClientToDoc and DocToClient methods.
**     * Modified OnDraw method to paint the view.
** 26-Nov-01 Edwin Chan
**     * Removed method OnCancelMode
**     * Added new methods OnEditProperties, and OnUpdateEditProperties
**     * Added new method IsSelected
**     * Modified method Select
**     * Changed m_SelectSet to public
** 28-Nov-01 Satish Hota
**     Made the CDrawable class CDrawableElement and created a CDrawable
**     super-class.  Hence, replaced usage of CDrawable with CDrawableElement.
** 30-Nov-01 Satish Hota
**     Modified the OnDraw method.  Calling the modified Document->Draw method
**     and getting the extents of the document after drawing.  Added an 
**     ObjectAt method.
** 01-Dec-01 Edwin Chan
**     Added ON_UPDATE_COMMAND_UI to the formation rule buttons so that 
**     they can only be used in SheetofAssertion view mode.
** 03-Dec-01 Edwin Chan, Satish Hota
**     Implemented OnRulesJoin and OnRulesDetach methods.
******************************************************************************/


#include "stdafx.h"
#include "ConGraT.h"

#include "ConGraTDoc.h"
#include "ConGraTView.h"

#include "CmdTool.h"
#include "SelectCmd.h"
#include "WarnDlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CConGraTView

IMPLEMENT_DYNCREATE(CConGraTView, CScrollView)

BEGIN_MESSAGE_MAP(CConGraTView, CScrollView)
	//{{AFX_MSG_MAP(CConGraTView)
	ON_COMMAND(ID_RULES_COPY, OnRulesCopy)
	ON_COMMAND(ID_RULES_SIMPLIFY, OnRulesSimplify)
	ON_COMMAND(ID_RULES_RESTRICT, OnRulesRestrict)
	ON_COMMAND(ID_RULES_UNRESTRICT, OnRulesUnrestrict)
	ON_COMMAND(ID_RULES_JOIN, OnRulesJoin)
	ON_COMMAND(ID_RULES_DETACH, OnRulesDetach)
	ON_COMMAND(ID_DRAW_SELECT, OnDrawSelect)
	ON_UPDATE_COMMAND_UI(ID_DRAW_SELECT, OnUpdateDrawSelect)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_VIEW_TYPEHIERARCHY, OnViewTypehierarchy)
	ON_UPDATE_COMMAND_UI(ID_VIEW_TYPEHIERARCHY, OnUpdateViewTypehierarchy)
	ON_COMMAND(ID_VIEW_RELATIONHIERARCHY, OnViewRelationhierarchy)
	ON_UPDATE_COMMAND_UI(ID_VIEW_RELATIONHIERARCHY, OnUpdateViewRelationhierarchy)
	ON_COMMAND(ID_VIEW_CATALOGOFINDIVIDUALS, OnViewCatalogofindividuals)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CATALOGOFINDIVIDUALS, OnUpdateViewCatalogofindividuals)
	ON_COMMAND(ID_VIEW_SHEETOFASSERTION, OnViewSheetofassertion)
	ON_UPDATE_COMMAND_UI(ID_VIEW_SHEETOFASSERTION, OnUpdateViewSheetofassertion)
	ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectall)
	ON_UPDATE_COMMAND_UI(ID_RULES_COPY, OnUpdateRulesCopy)
	ON_UPDATE_COMMAND_UI(ID_RULES_DETACH, OnUpdateRulesDetach)
	ON_UPDATE_COMMAND_UI(ID_RULES_JOIN, OnUpdateRulesJoin)
	ON_UPDATE_COMMAND_UI(ID_RULES_RESTRICT, OnUpdateRulesRestrict)
	ON_UPDATE_COMMAND_UI(ID_RULES_SIMPLIFY, OnUpdateRulesSimplify)
	ON_UPDATE_COMMAND_UI(ID_RULES_UNRESTRICT, OnUpdateRulesUnrestrict)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()

static CSelectCmd SelectCmd;

/////////////////////////////////////////////////////////////////////////////
// CConGraTView construction/destruction

CConGraTView::CConGraTView()
{
	// TODO: add construction code here
	m_eCurrentCmd = CmdType_Select;
	m_eCurrentView = ViewType_SheetOfAssertion;
}

CConGraTView::~CConGraTView()
{
}

BOOL CConGraTView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CConGraTView drawing

void CConGraTView::OnDraw(CDC* pDC)
{
	CConGraTDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here

	CDC dc;
	CDC* pDrawDC = pDC;
	CBitmap bitmap;
	CBitmap* pOldBitmap;

	// only paint the rect that needs repainting
	CRect client;
	pDC->GetClipBox(client);
	CRect rect = client;
	DocToClient(rect);

	if (!pDC->IsPrinting())
	{
		// draw to offscreen bitmap for fast looking repaints
		if (dc.CreateCompatibleDC(pDC))
		{
			if (bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()))
			{
				OnPrepareDC(&dc, NULL);
				pDrawDC = &dc;

				// offset origin more because bitmap is just piece of the whole drawing
				dc.OffsetViewportOrg(-rect.left, -rect.top);
				pOldBitmap = dc.SelectObject(&bitmap);
				dc.SetBrushOrg(rect.left % 8, rect.top % 8);

				// might as well clip to the same rectangle
				dc.IntersectClipRect(client);
			}
		}
	}

	// paint background
	CBrush brush;
	if (!brush.CreateSolidBrush(RGB(255, 255, 255)))
		return;

	brush.UnrealizeObject();
	pDrawDC->FillRect(client, &brush);

	pDoc->Draw(pDrawDC, this, m_eCurrentView);

    int nFromX, nFromY, nToX, nToY;
    pDoc->GetFromLocation(&nFromX, &nFromY);
    pDoc->GetToLocation(&nToX, &nToY);

	if (pDrawDC != pDC)
	{
		pDC->SetViewportOrg(0, 0);
		pDC->SetWindowOrg(0,0);
		pDC->SetMapMode(MM_TEXT);
		dc.SetViewportOrg(0, 0);
		dc.SetWindowOrg(0,0);
		dc.SetMapMode(MM_TEXT);
		pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),
			&dc, 0, 0, SRCCOPY);
		dc.SelectObject(pOldBitmap);

		pDC->SetViewportOrg(nFromX, nFromY);
        SetScrollSizes(MM_TEXT, CSize(nToX-nFromX, nToY-nFromY));
	}
}

void CConGraTView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx = sizeTotal.cy = 300;
	SetScrollSizes(MM_TEXT, sizeTotal);
    /*
	CSize size = GetDocument()->GetSize();
	CClientDC dc(NULL);
	size.cx = MulDiv(size.cx, dc.GetDeviceCaps(LOGPIXELSX), 100);
	size.cy = MulDiv(size.cy, dc.GetDeviceCaps(LOGPIXELSY), 100);
	SetScrollSizes(MM_TEXT, size);
    */
}

/////////////////////////////////////////////////////////////////////////////
// CConGraTView printing

BOOL CConGraTView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CConGraTView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CConGraTView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CConGraTView diagnostics

#ifdef _DEBUG
void CConGraTView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CConGraTView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CConGraTDoc* CConGraTView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CConGraTDoc)));
	return (CConGraTDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CConGraTView message handlers

void CConGraTView::OnRulesCopy() 
{
	CWarnDlg wdlg;

	wdlg.DoModal();

	// Set the current command to copy
    m_eCurrentCmd = CmdType_Copy;

	// Check size of m_SelectSet
    if(!m_SelectSet.empty())
    {
        // pass the m_SelectSet to CGEngine
    }

	// reset the current command
    m_eCurrentCmd = CmdType_Select;

    // Update entire client area
    Invalidate(FALSE);
}

void CConGraTView::OnRulesSimplify() 
{
	CWarnDlg wdlg;

	wdlg.DoModal();

	// Set the current command to simplify
    m_eCurrentCmd = CmdType_Simplify;

	// Check size of m_SelectSet
    if(!m_SelectSet.empty())
    {
	    // pass the m_SelectSet to CGEngine
    }

	// reset the current command
    m_eCurrentCmd = CmdType_Select;

    // Update entire client area
    Invalidate(FALSE);
}

void CConGraTView::OnRulesRestrict() 
{
	// Set the current command to restrict
    m_eCurrentCmd = CmdType_Restrict;

	// Check size of m_SelectSet
    if(m_SelectSet.size() == 1)
    {
        //pop up the properties dialog box
        SelectCmd.OnEditProperties(this);
        // pass the m_SelectSet to CGEngine

    }

	// reset the current command
    m_eCurrentCmd = CmdType_Select;

    // Update entire client area
    Invalidate(FALSE);
}

void CConGraTView::OnRulesUnrestrict() 
{
	// Set the current command to unrestrict
    m_eCurrentCmd = CmdType_Unrestrict;

	// Check size of m_SelectSet
    if(m_SelectSet.size() == 1)
    {
        //pop up the properties dialog box
        SelectCmd.OnEditProperties(this);
        // pass the m_SelectSet to CGEngine

    }

	// reset the current command
    m_eCurrentCmd = CmdType_Select;

    // Update entire client area
    Invalidate(FALSE);
}

void CConGraTView::OnRulesJoin() 
{
    CMFCDevConHelper devConHelper((CView *)this, NULL);
    CDrawableElement::SetDevConHelper(&devConHelper);

	// Set the current command to join
    m_eCurrentCmd = CmdType_Join;

	// Check size of m_SelectSet
    if(m_SelectSet.size() == 2)
    {
        CDrawableElement *pDrawableElement1, *pDrawableElement2;
		pDrawableElement1 = m_SelectSet[0];
		pDrawableElement2 = m_SelectSet[1];

		// Clear the select set
		Select(NULL, false);
		m_SelectSet[0]->DoJoin(m_SelectSet[1]);
        // pass the m_SelectSet to CGEngine
    }

    // reset the current command
    m_eCurrentCmd = CmdType_Select;

    CDrawableElement::SetDevConHelper(NULL);

    // Update entire client area
    Invalidate(FALSE);
}

void CConGraTView::OnRulesDetach() 
{
    CMFCDevConHelper devConHelper((CView *)this, NULL);
    CDrawableElement::SetDevConHelper(&devConHelper);

	// TODO: Add your command handler code here
	// Set the current command to detach
    m_eCurrentCmd = CmdType_Detach;

	// Check size of m_SelectSet
    if(m_SelectSet.size() == 1)
    {
        CDrawableElement* pDrawableElement;
		pDrawableElement = m_SelectSet[0];

		// Clear the select set
		Select(NULL, false);

		// pass the m_SelectSet to CGEngine
		pDrawableElement->DoDetach();

    }

	// reset the current command
    m_eCurrentCmd = CmdType_Select;

    CDrawableElement::SetDevConHelper(NULL);

    // Update entire client area
    Invalidate(FALSE);
}

void CConGraTView::OnDrawSelect() 
{
	// TODO: Add your command handler code here
	
}

void CConGraTView::OnUpdateDrawSelect(CCmdUI* pCmdUI) 
{
    // Always true because we have only one Draw Command
	pCmdUI->SetRadio(m_eCurrentCmd == CmdType_Select);
}

void CConGraTView::OnLButtonDown(UINT nFlags, CPoint point) 
{
    switch(m_eCurrentCmd)
    {
        case CmdType_Select:
        {
            SelectCmd.OnLButtonDown(this, nFlags, point);
            break;
        }
    }
}

void CConGraTView::OnLButtonUp(UINT nFlags, CPoint point) 
{
    switch(m_eCurrentCmd)
    {
        case CmdType_Select:
        {
            SelectCmd.OnLButtonUp(this, nFlags, point);
            break;
        }
    }
}

void CConGraTView::OnMouseMove(UINT nFlags, CPoint point) 
{
    switch(m_eCurrentCmd)
    {
        case CmdType_Select:
        {
            SelectCmd.OnMouseMove(this, nFlags, point);
            break;
        }
    }
	this->Invalidate(FALSE);
}

void CConGraTView::OnViewTypehierarchy() 
{
	m_eCurrentView = ViewType_TypeHierarchy;
    Invalidate(FALSE);
}

void CConGraTView::OnUpdateViewTypehierarchy(CCmdUI* pCmdUI) 
{
    pCmdUI->SetCheck(m_eCurrentView == ViewType_TypeHierarchy);	
}

void CConGraTView::OnViewRelationhierarchy() 
{
	m_eCurrentView = ViewType_RelationHierarchy;
    Invalidate(FALSE);
}

void CConGraTView::OnUpdateViewRelationhierarchy(CCmdUI* pCmdUI) 
{
    pCmdUI->SetCheck(m_eCurrentView == ViewType_RelationHierarchy);		
}

void CConGraTView::OnViewCatalogofindividuals() 
{
    m_eCurrentView = ViewType_CatalogOfIndividuals;	
    Invalidate(FALSE);
}

void CConGraTView::OnUpdateViewCatalogofindividuals(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_eCurrentView == ViewType_CatalogOfIndividuals);	
}

void CConGraTView::OnViewSheetofassertion() 
{
    m_eCurrentView = ViewType_SheetOfAssertion;	
    Invalidate(FALSE);
}

void CConGraTView::OnUpdateViewSheetofassertion(CCmdUI* pCmdUI) 
{
    pCmdUI->SetCheck(m_eCurrentView == ViewType_SheetOfAssertion);		
}

void CConGraTView::Select(CDrawableElement *pObj, bool b_AddSel)
{
    if(pObj == NULL)
    {
        //unselect all objects
        //update the object's m_bSelected
    
        std::vector<CDrawableElement*>::iterator vi;
        for(vi=m_SelectSet.begin();vi!=m_SelectSet.end();vi++)
	    {
            CDrawableElement* pObj = *vi;
		    pObj->UnSelect();
	    }
        //update the m_SelectSet
        m_SelectSet.clear();
    }
    else
    {
        if (!b_AddSel)
        {
			std::vector<CDrawableElement*>::iterator vi;
			for(vi=m_SelectSet.begin();vi!=m_SelectSet.end();vi++)
			{
				CDrawableElement* pObj = *vi;
		        pObj->UnSelect();
			}
            m_SelectSet.clear();
        }
        //select the given object
        //update the object's m_bSelected
        pObj->Select();
        //update the m_SelectSet
        m_SelectSet.push_back(pObj);
    }
}

bool CConGraTView::IsSelected(CDrawableElement *pObj)
{
    return pObj->IsSelected();
}

void CConGraTView::DocToClient(CRect &rect)
{
	CClientDC dc(this);
	OnPrepareDC(&dc, NULL);
	dc.LPtoDP(rect);
	rect.NormalizeRect();
}

void CConGraTView::DocToClient(CPoint &point)
{
	CClientDC dc(this);
	OnPrepareDC(&dc, NULL);
	dc.LPtoDP(&point);
}

void CConGraTView::ClientToDoc(CPoint &point)
{
	CClientDC dc(this);
	OnPrepareDC(&dc, NULL);
	dc.DPtoLP(&point);
}

void CConGraTView::ClientToDoc(CRect &rect)
{
	CClientDC dc(this);
	OnPrepareDC(&dc, NULL);
	dc.DPtoLP(rect);
	ASSERT(rect.left <= rect.right);
	ASSERT(rect.bottom <= rect.top);
}

/*
void CConGraTView::OnEditProperties() 
{
	if(m_SelectSet.size() ==1 && m_eCurrentCmd == CmdType_Select)
	{
		SelectCmd.OnEditProperties(this);
		this->Invalidate(FALSE);
	}
}
*/
/*
void CConGraTView::OnUpdateEditProperties(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_SelectSet.size() == 1 &&
				   m_eCurrentCmd == CmdType_Select);
}
*/

VDrawableElement CConGraTView::GetSelectSet()
{
    return m_SelectSet;
}

void CConGraTView::OnEditSelectall() 
{
    // TODO: Add your command handler code here
    VDrawableElement::iterator vi;
    VDrawableElement vSelect;
    vSelect = this->GetDocument()->m_pTempObjList;

	for(vi=vSelect.begin();vi!=vSelect.end();vi++)
	{
		CDrawableElement* pObj = *vi;
        pObj->Select();
        m_SelectSet.push_back(pObj);
	}
    Invalidate(FALSE);
}

CDrawableElement* CConGraTView::ObjectAt(const CPoint &point)
{
    return GetDocument()->ObjectAt(point, m_eCurrentView);
}

void CConGraTView::OnUpdateRulesCopy(CCmdUI* pCmdUI) 
{
    pCmdUI->Enable(m_eCurrentView == ViewType_SheetOfAssertion);
}

void CConGraTView::OnUpdateRulesDetach(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_eCurrentView == ViewType_SheetOfAssertion);
}

void CConGraTView::OnUpdateRulesJoin(CCmdUI* pCmdUI) 
{
    pCmdUI->Enable(m_eCurrentView == ViewType_SheetOfAssertion);	
}

void CConGraTView::OnUpdateRulesRestrict(CCmdUI* pCmdUI) 
{
    pCmdUI->Enable(m_eCurrentView == ViewType_SheetOfAssertion);
}

void CConGraTView::OnUpdateRulesSimplify(CCmdUI* pCmdUI) 
{
    pCmdUI->Enable(m_eCurrentView == ViewType_SheetOfAssertion);	
}

void CConGraTView::OnUpdateRulesUnrestrict(CCmdUI* pCmdUI) 
{
    pCmdUI->Enable(m_eCurrentView == ViewType_SheetOfAssertion);	
}

CmdType CConGraTView::GetCurrentCmd()
{
    return m_eCurrentCmd;
}
