// Rule.cpp: implementation of the CMyRule class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Rule.h"
#include "RulesBackgroundStatic.h"
#include <math.h>

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

#define HOT_POINT_RANGE				3		// ÈÈµãµÄ·¶Î§

static void DrawLine(CDC* pDC, CPoint beginPoint,CPoint endPoint, int drc, CMyRulesStatic* pWnd)
{
    if (beginPoint.x == endPoint.x && beginPoint.y == endPoint.y)
    {
        return;
    }
	CPen*   pOldPen;
    pOldPen = pDC->SelectObject(&pWnd->m_pen_normal_line);
    pDC->MoveTo(beginPoint.x, beginPoint.y);
    pDC->LineTo(endPoint.x,   endPoint.y);
	double PRECISION = 1.0e-10;

#if 1
    double radians;

	if(beginPoint.y == endPoint.y)
	{
		radians = 3.1415926535 / 2;
	}
	else
	{
		radians = (((double)(beginPoint.x - endPoint.x)/(double)(beginPoint.y - endPoint.y)));
		radians = atan(radians);
	}
	
	CDC sourceDC;
	sourceDC.CreateCompatibleDC(NULL);
	HDC hDC = pDC->m_hDC;
	BITMAP bm;
	GetObject(pWnd->m_hBmpTargent,sizeof(bm),&bm);
	float cosine = (float)cos(radians);
	float sine = (float)sin(radians);
	
	int x1 = (int)(bm.bmHeight * sine);
	int y1 = (int)(bm.bmHeight * cosine);
	int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
	int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
	int x3 = (int)(bm.bmWidth * cosine);
	int y3 = (int)(-bm.bmWidth * sine);
	int minx = min(0,min(x1, min(x2,x3)));
	int miny = min(0,min(y1, min(y2,y3)));
	POINT startPoint;

	startPoint.x = (beginPoint.x + endPoint.x) / 2;
 	startPoint.y = (beginPoint.y + endPoint.y) / 2;
	HBITMAP hbmOldSource;
	hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, pWnd->m_hBmpTargent);
	SetGraphicsMode(hDC, GM_ADVANCED);
	XFORM xform; 
	XFORM oldXForm;

	xform.eM11 = (drc == LINE_DRC_LEFT) ? (beginPoint.y <= endPoint.y ? -fabs(cosine) : fabs(cosine)):(beginPoint.y <= endPoint.y ? fabs(cosine):-fabs(cosine));
	xform.eM12 = (drc == LINE_DRC_LEFT) ? (beginPoint.x <= endPoint.x ? fabs(sine) : -fabs(sine)):(beginPoint.x <= endPoint.x ? -fabs(sine):fabs(sine));
	
	xform.eM21 = sine;
	xform.eM22 = cosine;
	xform.eDx = (float)-minx;
	xform.eDy = (float)-miny;
	
	GetWorldTransform( hDC, &oldXForm);
	SetWorldTransform( hDC, &xform);
	DPtoLP(hDC,&startPoint,1);
	TransparentBlt(hDC,startPoint.x,startPoint.y,bm.bmWidth, bm.bmHeight, sourceDC.m_hDC, 0, 0,bm.bmWidth, bm.bmHeight,RGB(255,255,255));

	if(drc == LINE_DRC_DOUBLE )
	{
		xform.eM11 = -xform.eM11;	
		xform.eM12 = -xform.eM12;
		startPoint.x = (beginPoint.x + endPoint.x) / 2;
		startPoint.y = (beginPoint.y + endPoint.y) / 2;
		
		SetWorldTransform( hDC, &xform);
		DPtoLP(hDC,&startPoint,1);
		TransparentBlt(hDC,startPoint.x,startPoint.y,bm.bmWidth, bm.bmHeight, sourceDC.m_hDC, 0, 0,bm.bmWidth, bm.bmHeight,RGB(255,255,255));		
	}
	SetWorldTransform(hDC, &oldXForm);
#endif
    
    pDC->SelectObject( pOldPen );
}

static void DrawHotPoint(CDC * pDC, CPoint point)
{
	COLORREF color = RGB(255,0,0);
	CBrush brush(color), *oldbrush;
	oldbrush = pDC->SelectObject(&brush);
	pDC->Rectangle(point.x-HOT_POINT_RANGE,point.y-HOT_POINT_RANGE,point.x+HOT_POINT_RANGE,point.y+HOT_POINT_RANGE);
	pDC->SelectObject(oldbrush);
	brush.DeleteObject();
}

static void DrawSelectPoint(CDC * pDC, CPoint point)
{
	COLORREF color = RGB(255,0,0);
	CBrush brush(color), *oldbrush;
	oldbrush = pDC->SelectObject(&brush);
	pDC->Rectangle(point.x-HOT_POINT_RANGE,point.y-HOT_POINT_RANGE,point.x+HOT_POINT_RANGE,point.y+HOT_POINT_RANGE);
	pDC->SelectObject(oldbrush);
	brush.DeleteObject();
}

static UINT create_32bit_reverse(UINT src)
{
	UINT i, ith_bit;
	UINT result = 0;
	
	/* Bits 1 through 15 occupy bits 31 through 16 of result */
	UINT shift_amount = 31;

	for(i = 0; i < 16; i++)
	{
		ith_bit = (src & (1 << i));
		result |= (ith_bit << shift_amount);
		shift_amount -= 2;
	}
	
	/* Bits 16 through 31 occupy bits 15 through 0 of result */
	shift_amount = 1;
	for(i = 16; i < 32; i++)
	{
		ith_bit = (src & (1 << i));
		result |= (ith_bit >> shift_amount);
		shift_amount += 2;
	}
	
	return (result);
}
//////////////////////////////////////////////////////////////////////
// CMyRule Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMyRule::CMyRule()
{
}

CMyRule::~CMyRule()
{

}

//////////////////////////////////////////////////////////////////////
// CSingleLineRule Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSingleLineRule::CSingleLineRule()
{
    m_ruleType          = RULE_TYPE_SINGLELINE;
    m_pHotPointLine     = NULL;
    m_hotPoint          = SINGLELINE_HOTPOINT_NONE;

    m_bMultiSegment     = FALSE;  

    m_Rule.m_sgline_flg   = 1;
    m_Rule.m_sgline_beg_x = 0;
    m_Rule.m_sgline_beg_y = 0;
    m_Rule.m_sgline_end_x = 0;
    m_Rule.m_sgline_end_y = 0;
    m_Rule.m_sgline_drc   = LINE_DRC_LEFT;

    m_pNextLine     = NULL;
    m_pHotPointLine = NULL;
    m_bInitDraw     = FALSE;
    m_bFinish       = FALSE;
	m_ruleName      = _T("");
	m_bEnable       = TRUE;
	m_ruleTypeName  = _T("");
}

CSingleLineRule::CSingleLineRule(CSingleLineRule* pCopyRule)
{
    m_ruleType          = RULE_TYPE_SINGLELINE;
    m_pHotPointLine     = NULL;
	m_pNextLine         = NULL;
    m_hotPoint          = SINGLELINE_HOTPOINT_NONE;
    m_bMultiSegment     = pCopyRule->m_bMultiSegment;

	m_ruleName          = _T("");
	m_ruleTypeName      = pCopyRule->m_ruleTypeName;
	m_bEnable           = pCopyRule->m_bEnable;

    m_Rule.m_sgline_flg   = pCopyRule->m_Rule.m_sgline_flg;
    m_Rule.m_sgline_beg_x = pCopyRule->m_Rule.m_sgline_beg_x;
    m_Rule.m_sgline_beg_y = pCopyRule->m_Rule.m_sgline_beg_y;
    m_Rule.m_sgline_end_x = pCopyRule->m_Rule.m_sgline_end_x;
    m_Rule.m_sgline_end_y = pCopyRule->m_Rule.m_sgline_end_y;
    m_Rule.m_sgline_drc   = pCopyRule->m_Rule.m_sgline_drc;
	m_Rule.m_sgline_name[0] = '\0';

	m_bInitDraw = pCopyRule->m_bInitDraw;
	m_bFinish   = pCopyRule->m_bFinish;

    if( pCopyRule->m_pNextLine )
    {
        m_pNextLine = new CSingleLineRule(pCopyRule->m_pNextLine);
    }
}

CSingleLineRule::~CSingleLineRule()
{
    if( m_pNextLine )
    {
        delete m_pNextLine;
        m_pNextLine = NULL;
    }
}

void CSingleLineRule::DrawRule(CDC* pDC, CMyRulesStatic* pWnd)
{
    DrawLine(pDC, CPoint(m_Rule.m_sgline_beg_x,m_Rule.m_sgline_beg_y),
        CPoint(m_Rule.m_sgline_end_x,m_Rule.m_sgline_end_y),
        m_Rule.m_sgline_drc, pWnd);
    
    DrawHotPoint(pDC, CPoint(m_Rule.m_sgline_beg_x, m_Rule.m_sgline_beg_y));
    DrawHotPoint(pDC, CPoint(m_Rule.m_sgline_end_x, m_Rule.m_sgline_end_y));
    
    if (m_pNextLine)
    {
		try
		{
			m_pNextLine->DrawRule(pDC, pWnd);
		}
		catch(...){}
    }
}

void CSingleLineRule::MoveRule(int offset_x, int offset_y)
{
    if( (m_Rule.m_sgline_beg_x + offset_x > 0 && m_Rule.m_sgline_beg_x + offset_x <= 352) &&
        (m_Rule.m_sgline_beg_y + offset_y > 0 && m_Rule.m_sgline_beg_y + offset_y <= 288) &&
        (m_Rule.m_sgline_end_x + offset_x > 0 && m_Rule.m_sgline_end_x + offset_x <= 352) &&
        (m_Rule.m_sgline_end_y + offset_y > 0 && m_Rule.m_sgline_end_y + offset_y <= 288))
    {
        m_Rule.m_sgline_beg_x += offset_x;
        m_Rule.m_sgline_beg_y += offset_y;
        m_Rule.m_sgline_end_x += offset_x;
        m_Rule.m_sgline_end_y += offset_y;
    }
}

//////////////////////////////////////////////////////////////////////
// CDoubleLineRule Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDoubleLineRule::CDoubleLineRule()
{
    m_Rule.m_dbline_flg = 1;
    m_ruleType = RULE_TYPE_DOUBLELINE;
	m_ruleName = _T("");
	m_bEnable  = TRUE;
	m_ruleTypeName = _T("");
}

CDoubleLineRule::~CDoubleLineRule()
{

}

void CDoubleLineRule::DrawRule(CDC* pDC, CMyRulesStatic* pWnd)
{

}

void CDoubleLineRule::MoveRule(int offset_x, int offset_y)
{

}

//////////////////////////////////////////////////////////////////////
// CReginLineRule Construction/Destruction
//////////////////////////////////////////////////////////////////////

CRegionRule::CRegionRule(int regionDrc)
{
    m_ruleType = RULE_TYPE_REGION;
	m_ruleTypeName = _T("");
    memset(&m_Rule,0,sizeof(RegionAlarm));
    m_Rule.m_region_flg = 1;
    m_regionDrc = regionDrc;
  
    CRect rcRgn;

    if (m_regionDrc == -1)
    {
        rcRgn = CRect(0, 0, 0, 0);
    }
    else
    {
        rcRgn = CRect (0, 0, 352, 288);
        if (m_regionDrc == 1)
        {
            rcRgn.InflateRect(-16, -16);
        }
    }
    m_rgn.CreateRectRgnIndirect(&rcRgn);
	m_ruleName = _T("");
	m_bEnable  = TRUE;
}

CRegionRule::~CRegionRule()
{
	m_rgn.DeleteObject();
}

void CRegionRule::DrawRule(CDC* pDC, CMyRulesStatic* pWnd)
{
}

void CRegionRule::MoveRule(int offset_x, int offset_y)
{

}

void CSingleLineRule::EditSingleLineRule(int offset_x, int offset_y, int editActionType)
{
    CSingleLineRule *pNextLine;

    if (m_bMultiSegment && editActionType == EDITRULE_ACTION_HOTPOINT)
    {
        pNextLine = m_pHotPointLine?m_pHotPointLine:this;
    }
    else
    {
        pNextLine = this;
    }

    while (pNextLine)
    {
        if ( editActionType  == EDITRULE_ACTION_MOVEING
          || (editActionType == EDITRULE_ACTION_HOTPOINT 
          && m_hotPoint == SINGLELINE_HOTPOINT_BEGIN))
        {
            pNextLine->m_Rule.m_sgline_beg_x += offset_x;
            pNextLine->m_Rule.m_sgline_beg_y += offset_y;
        }

        if ( editActionType == EDITRULE_ACTION_MOVEING
          || (editActionType == EDITRULE_ACTION_HOTPOINT 
          &&  m_hotPoint == SINGLELINE_HOTPOINT_END))
        {
            pNextLine->m_Rule.m_sgline_end_x += offset_x;
            pNextLine->m_Rule.m_sgline_end_y += offset_y;
        }

        if( editActionType != EDITRULE_ACTION_MOVEING )
        {
            if ((pNextLine != this || !(editActionType == EDITRULE_ACTION_HOTPOINT && m_hotPoint == SINGLELINE_HOTPOINT_BEGIN))
              && pNextLine->m_pNextLine)
            {
                pNextLine->m_pNextLine->m_Rule.m_sgline_beg_x += offset_x;
                pNextLine->m_pNextLine->m_Rule.m_sgline_beg_y += offset_y;
            }
            break;
        }

        pNextLine = pNextLine->m_pNextLine;
    }
}

BOOL CSingleLineRule::CheckHotPoint(CPoint point)
{
    CSingleLineRule* pSingleRule = this;

    m_hotPoint = SINGLELINE_HOTPOINT_NONE;

    if (!m_bInitDraw)
    {
        m_Rule.m_sgline_beg_x = point.x;
        m_Rule.m_sgline_beg_y = point.y;
        m_Rule.m_sgline_end_x = point.x;
        m_Rule.m_sgline_end_y = point.y;
        m_hotPoint          = SINGLELINE_HOTPOINT_END;
        m_bInitDraw         = TRUE;
        return TRUE;
    }

    while (pSingleRule)
    {
        if ( pSingleRule == this 
            && point.x >= pSingleRule->m_Rule.m_sgline_beg_x-HOT_POINT_RANGE
            && point.x <= pSingleRule->m_Rule.m_sgline_beg_x+HOT_POINT_RANGE
            && point.y >= pSingleRule->m_Rule.m_sgline_beg_y-HOT_POINT_RANGE
            && point.y <= pSingleRule->m_Rule.m_sgline_beg_y+HOT_POINT_RANGE)
        {
            m_pHotPointLine = pSingleRule;
            m_hotPoint = SINGLELINE_HOTPOINT_BEGIN;
		    return TRUE;
        }
        else if (point.x >= pSingleRule->m_Rule.m_sgline_end_x-HOT_POINT_RANGE 
                && point.x <= pSingleRule->m_Rule.m_sgline_end_x+HOT_POINT_RANGE
                && point.y >= pSingleRule->m_Rule.m_sgline_end_y-HOT_POINT_RANGE
                && point.y <= pSingleRule->m_Rule.m_sgline_end_y+HOT_POINT_RANGE)
        {
            m_pHotPointLine = pSingleRule;
            m_hotPoint = SINGLELINE_HOTPOINT_END;
            return TRUE;
        }

        pSingleRule = pSingleRule->m_pNextLine;
    }
    return FALSE;
}

void CSingleLineRule::SetDirection(int direction)
{
    m_Rule.m_sgline_drc = direction;

    if( m_bMultiSegment )
    {
        CSingleLineRule* pNextLine;
        
        pNextLine = m_pNextLine;
        while( pNextLine )
        {
            pNextLine->m_Rule.m_sgline_drc = direction;

            pNextLine = pNextLine->m_pNextLine;
        }
    }
}

CSingleLineRule* CSingleLineRule::GetLastSegment()
{
    CSingleLineRule*   pLastSegment = this;

    while( pLastSegment->m_pNextLine )
    {
        pLastSegment = pLastSegment->m_pNextLine;
    }

    return pLastSegment;
}

int CSingleLineRule::GetLineCount()
{
    int              lineCount = 0;
    CSingleLineRule* pNextLine;

    pNextLine = this;
    while (pNextLine)
    {
		if(pNextLine->m_Rule.m_sgline_beg_x == 0 && pNextLine->m_Rule.m_sgline_beg_y == 0 &&
			pNextLine->m_Rule.m_sgline_end_x == 0 &&pNextLine->m_Rule.m_sgline_end_y == 0)
			break;
        lineCount++;
        pNextLine = pNextLine->m_pNextLine;
    }

    return lineCount;
}

void CSingleLineRule::CheckMultiLineRule(BOOL bCheck)
{
	m_bEnable = bCheck;
	CSingleLineRule *pSingleRule = this;
	while(pSingleRule != NULL)
	{
		pSingleRule->m_Rule.m_sgline_flg = bCheck;
		pSingleRule = pSingleRule->m_pNextLine;
	}
}

void CRegionRule::AddRegion(LPCRECT lpRect)
{
    CRgn   tmpRgn;
    
    tmpRgn.CreateRectRgn(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
    m_rgn.CombineRgn(&m_rgn, &tmpRgn, RGN_OR);
}

void CRegionRule::DelRegion(LPCRECT lpRect)
{
    CRgn   tmpRgn;
    
    tmpRgn.CreateRectRgn(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
    m_rgn.CombineRgn(&m_rgn, &tmpRgn, RGN_DIFF);
}

void CRegionRule::CleanAllRegion()
{
    m_rgn.SetRectRgn(0,0,0,0);
}

void CRegionRule::AddRect(LPCRECT lpRect)
{
    CRgn   tmpRgn;

    tmpRgn.CreateRectRgn(lpRect->left, lpRect->top, lpRect->right>=352?351:lpRect->right, lpRect->bottom>=288?287:lpRect->bottom);
    m_rgn.CombineRgn(&m_rgn, &tmpRgn, RGN_OR);
}

void CRegionRule::AddPolygon(LPPOINT lpPoint, int nCount)
{
    CRgn   tmpRgn;
    
    tmpRgn.CreatePolygonRgn(lpPoint, nCount, WINDING);
    m_rgn.CombineRgn(&m_rgn, &tmpRgn, RGN_OR);
}

void CSingleLineRule::SetRule(VSNETVASINGLELINERULE *pRule)
{
    m_Rule = *((SGLineAlarm*)pRule);
    m_bInitDraw = TRUE;
}

void CSingleLineRule::SetRule(VSNETVAMULTILINERULE* pRule)
{
    int index = 0;

    if (pRule->m_lineCount > 0 )
    {
        m_bInitDraw = TRUE;
        m_Rule = *((SGLineAlarm*)&pRule->m_multiline[0]);

        index = 1;
        CSingleLineRule*    pSingleLineRule = this;
        while (index < pRule->m_lineCount)
        {
            CSingleLineRule* pNewRule = new CSingleLineRule();
            pNewRule->m_bInitDraw = TRUE;
            pNewRule->m_Rule = *((SGLineAlarm*)&pRule->m_multiline[index]);

            pSingleLineRule->m_pNextLine = pNewRule;
            pSingleLineRule = pSingleLineRule->m_pNextLine;

            index++;
        }
    }
}

void CDoubleLineRule::SetRule(VSNETVADOUBLELINERULE *pRule)
{
    m_Rule = *((DBLineAlarm*)pRule);
}

void CRegionRule::SetRule(VSNETVAREGIONERULE *pRule)
{
    m_Rule = *((RegionAlarm*)pRule);
    
    CreateRgnFromRule();
}

void CRegionRule::CreateRgnFromRule()
{
    int     img_w,img_h;
    int     h,w,p;
    CRgn    tmpDstRgn;
	
    img_w = 352;
    img_h = 288;

    tmpDstRgn.CreateRectRgn(0,0,0,0);

    for(int pix = 0; pix < img_w*img_h/32; pix++)
	{
		m_Rule.m_packed_msk[pix] = create_32bit_reverse(m_Rule.m_packed_msk[pix]);
	}

    for(h = 0; h < img_h; h++)
	{
		for(w = 0; w < img_w/8; w++)
		{
            unsigned char packedvalue = 0;
            
            packedvalue = *((BYTE*)m_Rule.m_packed_msk + img_w/8*h + w);

            for(p = 0; p < 8; p++)
            {
                if (((packedvalue >> p) & 0x01) * 255)
                {
                    CRgn    tmpRgn;
                    tmpRgn.CreateRectRgn(8*w + p, h, 8*w + p + 1, h + 1);
                    tmpDstRgn.CombineRgn(&tmpDstRgn, &tmpRgn, RGN_OR);
                }
            }
		}
	}
    
    m_rgn.Detach();
    m_rgn.CreateRectRgn(0,0,0,0);
    m_rgn.CopyRgn(&tmpDstRgn);
}

void CRegionRule::GetRuleFromRgn(UINT *pDst)
{
#if 0
    char   *lpRgnData;
    int     nCount;

    nCount    = 352*288*sizeof(RECT) + sizeof(RGNDATAHEADER);
    lpRgnData = new char[nCount];

    if ( m_rgn.GetRegionData((LPRGNDATA)lpRgnData, nCount))
    {
        LPRECT  pRect = (LPRECT)((LPRGNDATA)lpRgnData)->Buffer;
        
        for(int index = 0; index < ((LPRGNDATA)lpRgnData)->rdh.nCount; index++)
        {
            UINT    word,pos;
            int     shift;
            
            shift = word = pos = 0;
            
            for(int x = pRect[index].left; x <= pRect[index].right; x++)
            {
                for(int y = pRect[index].top; y <= pRect[index].bottom; y++)
                {
                    TRACE("Save x:%d y:%d Region On\n", x, y);
                    word |= 1 << (31-shift);
            
                    if (shift == 31)
                    {
                        pDst[pos++] = word;
                        word  = 0;
                        shift = 0;
                    }
                    else
                    {
                        shift++;
                    }
                }
            }
            TRACE("Rect Agian\n");
        }
    }
#else
    UINT    word,pos;
    int     shift;
    int     img_w,img_h;
    int     h,w;

    img_w = 352;
    img_h = 288;

    shift = word = pos = 0;
    memset(pDst,0,352*288/8);

    CRgn    tmpRgn;
    tmpRgn.CreateRectRgn(0, 0, 0, 0);
    tmpRgn.CopyRgn(&m_rgn);

    for (h = 0; h < img_h; h++)
    {
        for (w = 0; w < img_w; w++)
        {           
            word |= ((m_rgn.PtInRegion(CPoint(w,h))?1:0) << (31-shift));
            
            if (shift == 31)
            {
                pDst[pos++] = word;
                word  = 0;
                shift = 0;
            }
            else
            {
                shift++;
            }
        }
    }
#endif
}

void CSingleLineRule::Reset()
{
    m_pHotPointLine     = NULL;
    m_hotPoint          = SINGLELINE_HOTPOINT_NONE;

    m_Rule.m_sgline_beg_x = 0;
    m_Rule.m_sgline_beg_y = 0;
    m_Rule.m_sgline_end_x = 0;
    m_Rule.m_sgline_end_y = 0;
    m_Rule.m_sgline_drc   = LINE_DRC_LEFT;

    m_pHotPointLine     = NULL;
    m_bInitDraw         = FALSE;

    if( m_pNextLine )
    {
        delete m_pNextLine;
        m_pNextLine = NULL;
    }

    m_bFinish           = FALSE;
}

void CSingleLineRule::FinishDraw()
{
    CSingleLineRule*    pPrevRule;
    CSingleLineRule*    pNextRule;

    if (m_bFinish)
    {
        return;
    }

    pPrevRule = this;
    pNextRule = pPrevRule->m_pNextLine;

    while (pNextRule != NULL && pNextRule->m_pNextLine != NULL)
    {
        pPrevRule = pNextRule;
        pNextRule = pPrevRule->m_pNextLine;
    }

    if (pNextRule)
    {
        delete pNextRule;
        pPrevRule->m_pNextLine = NULL;
    }

    m_bFinish = TRUE;
}
