// FloatEdit.cpp : implementation file
//

#include "stdafx.h"
//#include "admin.h"
#include "FloatEdit.h"

ULONG ulFloatErrCnt=0L;


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

/////////////////////////////////////////////////////////////////////////////
// CFloatEdit

CFloatEdit::CFloatEdit()
{
        m_bSilent=FALSE;
        m_bZeroIsBlank=TRUE;
}

CFloatEdit::~CFloatEdit()
{
}


BEGIN_MESSAGE_MAP(CFloatEdit, CEdit)
        //{{AFX_MSG_MAP(CFloatEdit)
                // NOTE - the ClassWizard will add and remove mapping macros here.
        ON_CONTROL_REFLECT(EN_KILLFOCUS, OnKillfocus)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFloatEdit message handlers

void FloatEditErr(CEdit *ctl, BOOL silent /*=FALSE*/)
{
        ulFloatErrCnt++;
        if (!silent)
                AfxMessageBox(ulFloatErrCnt>=3?"Please enter a valid floating point expression such as:\n   1/2\n   10 15/16\n   10.5\n   10 + 5\n   10.5 * 2\n   etc...":"Illegal floating point value.");
        ctl->SetSel(0,-1);
        ctl->SetFocus();
        if (ulFloatErrCnt==ULONG_MAX)
                ulFloatErrCnt=0L;
}

void CFloatEdit::OnKillfocus() 
{
        if (GetModify())
        {
                CString s;
                BOOL err=FALSE,result;
                GetWindowText(s);
                s.TrimLeft();
                s.TrimRight();
                result = Translate(s.GetBuffer(100));
                s.ReleaseBuffer();
                if (result && !(s.IsEmpty() && !m_bZeroIsBlank))
                {
                        SetWindowText(s);
                        ulFloatErrCnt=0L;
                }
                else
                        err=TRUE;
                if (err)
                        FloatEditErr(this, m_bSilent);
        }
}


BOOL CFloatEdit::Translate(LPSTR szFloatExpr)
{
        LPSTR p,pdiv,pdot,pop,limit,end;
        char op=' ',temp[100];
        float fmain,fcalc,result=0.f;

        limit = szFloatExpr+strlen(szFloatExpr);
        if (limit==szFloatExpr)
                return TRUE;

        pdiv=strchr(szFloatExpr,'/');
        pdot=strchr(szFloatExpr,'.');
        if ((pop=strchr(szFloatExpr+1,'*')) == NULL)
                if ((pop=strchr(szFloatExpr+1,'+')) == NULL)
                        if ((pop=strchr(szFloatExpr+1,'-')) == NULL)
                                if (pdiv != NULL)
                                        pop = strchr(pdiv+1,'/');

        if ((pdot!=NULL && pdiv != NULL && pdot < pdiv && (pdot < pop||pop==NULL)) // first number is fp
                || (pdot!=NULL && pdiv == NULL && pdot < pop))
                for (end=pdot+1; isdigit(*end) && *end != NULL; end++);
        else if (pdiv!=NULL && pdiv < pop)
                for (end=pdiv+1; isdigit(*end) && *end != NULL; end++);
        else if (pop!=NULL)
                end=pop;
        else
                for (end=szFloatExpr+1; *end != NULL && *end != '+' && *end != '-' && *end != '*'; end++);

        memcpy(temp,szFloatExpr,end-szFloatExpr);
        temp[end-szFloatExpr] = NULL;
        p=end;
        {
                if (!DecodeFloatString(temp,&fmain))
                        return FALSE;

                if (p >= limit)
                        result=fmain;
                else
                {
                        for (; *p == ' ' && *p != NULL; p++);  // skip whitespace
                        if (*p != '+' && *p != '-' && *p != '/' && *p != '*')
                                return FALSE;
                        op = *p++;
                        for (; *p == ' ' && *p != NULL; p++);  // skip whitespace
                        if (*p == NULL || !DecodeFloatString(p,&fcalc) || (op=='/'&&fcalc==0.f))
                                return FALSE;

                        switch(op)
                        {
                        case '+':
                                result = fmain + fcalc;
                                break;
                        case '-':
                                result = fmain - fcalc;
                                break;
                        case '*':
                                result = fmain * fcalc;
                                break;
                        case '/':
                                result = fmain / fcalc;
                                break;
                        }

                }
        }

        sprintf(szFloatExpr,"%1.4f",result);
        for (p=szFloatExpr+strlen(szFloatExpr)-1; p > szFloatExpr && *p=='0'; p--);
        if (*p=='.') // we don't want numbers like 4.
                *p=NULL;
        else
                *(p+1)=NULL;
        return TRUE;
}

BOOL CFloatEdit::DecodeFloatString(LPCSTR szFloatExpr, float *fResult)
{
        LPSTR p,pdiv;
        LPCSTR limit=szFloatExpr+strlen(szFloatExpr);
        float num,den;

        *fResult = 0.f;
        if ((p=strchr(szFloatExpr,'.')) == NULL
                && (pdiv=strchr(szFloatExpr,'/')) != NULL)
        {
                // look for numerator
                for (p=pdiv-1; p >= szFloatExpr && *p != ' '; p--); 
                num = (float)atof(p+1);
                
                // get main integer part, if it exists
                if (p+1!=szFloatExpr) 
                {
                        *p=NULL;
                        *fResult+=atoi(szFloatExpr);
                }
                
                den = (float)atof(pdiv+1);
                if (den==0)
                        return FALSE;
                *fResult += num/den;
        }
        else    // first number is fp decimal
                *fResult = (float)atof(szFloatExpr);
        return TRUE;
}

void CFloatEdit::TrimZeros(LPSTR szFloatExpr)
{
        LPSTR p;
        for (p=szFloatExpr+strlen(szFloatExpr)-1; p > szFloatExpr && *p=='0'; p--);
        if (*p=='.') // we don't want numbers like 4.
                *p=NULL;
        else
                *(p+1)=NULL;
}