/******************************************************************************
** Copyright (C) 2001, University of Alabama in Huntsville. All rights 
** reserved.
**
** File   : DrawableRectangle.cpp
**
** Author : Satish Hota
**
** Description:
**    This file provides implementation for CDrawableRectangle class.
**
** History:
** 21-Nov-01 Satish Hota
**     File Created
** 26-Nov-01 Satish Hota
**     Changed Draw implementation.
** 30-Nov-01 Satish Hota
**     Modified the Draw implementation to draw with different pen types.
**     Added and implemented the ClipLine method.
******************************************************************************/

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

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDrawableRectangle::CDrawableRectangle()
{

}

CDrawableRectangle::~CDrawableRectangle()
{

}

long CDrawableRectangle::Draw()
{
    int nWidth, nHeight;
    std::string strText;

    GetText(strText);
    c_pDevConHelper->GetTextExtents(strText, &nWidth, &nHeight);

    m_nToX = m_nFromX + nWidth + 2*c_nTextClearance;
    m_nToY = m_nFromY + nHeight + 2*c_nTextClearance;

    CMFCDevConHelper::PenType ePenType;
    
    if(m_bSelected)
    {
        ePenType = CMFCDevConHelper::PenType_Thick;
    }
    else
    {
        ePenType = CMFCDevConHelper::PenType_Solid;
    }

    c_pDevConHelper->DrawRectangle(m_nFromX, m_nFromY, m_nToX, m_nToY, ePenType);

    c_pDevConHelper->TextOut(m_nFromX+c_nTextClearance, m_nFromY+c_nTextClearance, strText);

    return CG_S_OK;
}

CDrawableRectangle::CDrawableRectangle(int l, int t, int r, int b)
{
    m_nFromX = l;
    m_nFromY = t;
    m_nToX = r;
    m_nToY = b;
}

long CDrawableRectangle::HitTest(int nXCoor, int nYCoor)
{
    CRgn region;

    if(!region.CreateRectRgn(m_nFromX, m_nFromY, m_nToX, m_nToY))
        return CG_E_FAIL;

	if(region.PtInRegion(nXCoor, nYCoor))
    {
        return RC_S_HitSucess;
    }
    else
    {
        return RC_S_HitFailue;
    }

    // Should not be coming here
    return CG_E_FAIL;
}

long CDrawableRectangle::ClipLine(int *pnFromX, int *pnFromY, int *pnToX, int *pnToY)
{
    CRgn region;

    if(!region.CreateRectRgn(m_nFromX, m_nFromY, m_nToX, m_nToY))
        return CG_E_FAIL;

    int nFromX, nFromY, nToX, nToY;
    nFromX = *pnFromX;
    nFromY = *pnFromY;
    nToX = *pnToX;
    nToY = *pnToY;

    bool bFromInside, bToInside;
    // Return if both the points are within the region or are out of the region.
    if(!((bFromInside = region.PtInRegion(nFromX, nFromY)) ^ 
         (bToInside = region.PtInRegion(nToX, nToY))))
        return CG_S_FALSE;

    // Calculate intersection with each line.


    /*
    ** From http://www.intermetrics.com/ecce/models/current/camim/geometry_model/line_intersect_line.html
    r, s : NUMBER;
    x, y, denominator : INTEGER;
    A := line1.start_point;
    B := line1.end_point;
    C := line2.start_point;
    D := line2.end_point;

    denominator := (B.x_coordinate - A.x_coordinate)
                * (D.y_coordinate - C.y_coordinate)
                - (B.y_coordinate - A.y_coordinate)
                   *(D.x_coordinate - C.x_coordinate);

    r := ((A.y_coordinate - C.y_coordinate)*(D.x_coordinate - C.x_coordinate) -
      (A.x_coordinate - C.x_coordinate)*(D.y_coordinate - C.y_coordinate))
     / denominator;

    s := ((A.y_coordinate - C.y_coordinate)*(B.x_coordinate - A.x_coordinate) -
      (A.x_coordinate - C.x_coordinate)*(B.y_coordinate - A.y_coordinate))
     / denominator;

    RETURN({0 < r < 1} AND {0 < s < 1});
    */

    double r, s, denominator;
    int x1, y1, x2, y2;

    x1 = m_nFromX;
    y1 = m_nFromY;
    x2 = m_nToX;
    y2 = m_nFromY;
    for(int i=0;i<4;i++)
    {
        switch(i)
        {
        case 0:
            x1 = m_nFromX;
            y1 = m_nFromY;
            x2 = m_nToX;
            y2 = m_nFromY;
            break;
        case 1:
            x1 = x2;
            y1 = y2;
            y2 = m_nToY;
            break;
        case 2:
            x1 = x2;
            y1 = y2;
            x2 = m_nFromX;
            break;
        case 3:
            x1 = x2;
            y1 = y2;
            y2 = m_nFromY;
        }

        denominator = (nToX - nFromX) * (y2-y1) - (nToY - nFromY) * (x2-x1);

        r = ((nFromY - y1)*(x2 - x1) - (nFromX - x1)*(y2-y1))/denominator;
        s = ((nFromY - y1)*(nToX - nFromX) - (nFromX - x1)*(nToY - nFromY))/denominator;

        if((r >= 0 && r <= 1) && (s>= 0 && s<=1))
        {
            if(bFromInside)
            {
                *pnFromX = nFromX + r*(nToX - nFromX);
                *pnFromY = nFromY + r*(nToY - nFromY);
            }
            else if(bToInside)
            {
                *pnToX = nFromX + r*(nToX - nFromX);
                *pnToY = nFromY + r*(nToY - nFromY);
            }
            else
            {
                return CG_E_FAIL;
            }

            return CG_S_OK;
        }
    }

    return CG_S_FALSE;
}
