/******************************************************************
  
  Module:  calculation.cpp
  
  Author: Sean Craig
  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

//-------------------------------------------------------- Includes
#include "calculation.h"
#include <stdio.h>
#include <vector>
//---------------------------------------------- Class Declarations

class cBonus
{
public:
  // determines order of operation
  typedef enum 
  {
    PRIORITY_ADD,
    PRIORITY_MULTIPLY,
    PRIORITY_SET,
    NUM_PRIORITIES

  } tPriority;

  cBonus(float value,const SyString &name);
  virtual ~cBonus(){};

  virtual tPriority GetPriority()=0;
  virtual float Apply(float input)=0;
  const SyString &GetName();
  virtual float Report(SyString *ans,float input)=0; // todo

protected:
  float         mValue;
  SyString      mName;
};


class cAddBonus : public cBonus
{
public:
  cAddBonus(float value,const SyString &name) : cBonus(value,name){};
  tPriority GetPriority(){return PRIORITY_ADD;};
  virtual float Apply(float input);
  virtual float Report(SyString *ans,float input);
  
};


class cMultiplyBonus : public cBonus
{
public:
  cMultiplyBonus(float value,const SyString &name): cBonus(value,name){};
  tPriority GetPriority(){return PRIORITY_MULTIPLY;};
  virtual float Apply(float input); 
  virtual float Report(SyString *ans,float input);
};


class cAddRandomBonus: public cBonus
{
public:
  cAddRandomBonus(int _min,int _max,const SyString &name);
  tPriority GetPriority(){return PRIORITY_ADD;};
  virtual float Apply(float input); 
  virtual float Report(SyString *ans,float input);
protected:
  int       mMin;
  int       mMax;
  bool      mRolled;
};


class cSetBonus : public cBonus
{
public:
  cSetBonus(float value,const SyString &name): cBonus(value,name){};
  tPriority GetPriority(){return PRIORITY_SET;};
  virtual float Apply(float input); 
  virtual float Report(SyString *ans,float input);
};


class cMinBonus : public cBonus
{
public:
  cMinBonus(float value,const SyString &name): cBonus(value,name){};
  tPriority GetPriority(){return PRIORITY_SET;};
  virtual float Apply(float input);
  virtual float Report(SyString *ans,float input);
};


class cMaxBonus : public cBonus
{
public:
  cMaxBonus(float value,const SyString &name): cBonus(value,name){};
  tPriority GetPriority(){return PRIORITY_SET;};
  virtual float Apply(float input);
  virtual float Report(SyString *ans,float input);
};

//--------------------------------------------------------- Globals
//----------------------------------------- Functions Declarations
//------------------------------------ Member Functions Definitions

//------------------------------------ cBonus

cBonus::cBonus(float value,const SyString &name) : mValue(value),mName(name)
{
}

const SyString &
cBonus::GetName()
{
  return mName;
};

//------------------------------------ cAddBonus

float 
cAddBonus::Apply(float input) 
{
  return input + mValue;
};

float 
cAddBonus::Report(SyString *ans,float input)
{
  char buffer[256];
  float result = Apply(input);
  sprintf(buffer,"%d+%d=%d\t\t\t%s\n",(int)input,(int)mValue,(int)result,mName.AsChar());
  *ans+=buffer;
  return result;
}

//------------------------------------ cMultiplyBonus

float 
cMultiplyBonus::Apply(float input) 
{
  return input * mValue;
};

float 
cMultiplyBonus::Report(SyString *ans,float input)
{
  char buffer[256];
  float result = Apply(input);
  sprintf(buffer,"%d*%0.4f=%d\t\t\t%s\n",(int)input,mValue,(int)result,mName.AsChar());
  *ans+=buffer;
  return result;
}


//------------------------------------ cRandomBonus

cAddRandomBonus::cAddRandomBonus(int _min,int _max,const SyString &description) : cBonus(0,description),
mMin(_min),mMax(_max),mRolled(false)
{
}

float 
cAddRandomBonus::Apply(float input) 
{                                                      
  if (!mRolled)
  {
    mValue = (float) (mMin+mMax)/2; // todo:random(mMin,mMax)
    mRolled = true;
  }
  return input + mValue;
};

float
cAddRandomBonus::Report(SyString *ans,float input)
{
  char buffer[256];
  float result = Apply(input);
  sprintf(buffer,"%d+%d(%d-%d)=%d\t\t\t%s\n",(int)input,(int)mValue,mMin,mMax,(int)result,mName.AsChar());
  *ans+=buffer;
  return result;
}

//------------------------------------ cSetBonus

float 
cSetBonus::Apply(float input) 
{
  return mValue;
};
float
cSetBonus::Report(SyString *ans,float input)
{
  char buffer[256];
  float result = Apply(input);
  sprintf(buffer,"=%d\t%s\n",(int)mValue,mName.AsChar());
  *ans+=buffer;
  return result;
}

//------------------------------------ cMinBonus

float 
cMinBonus::Apply(float input) 
{
  if (input < mValue)
  {
    return mValue;
  }
  return input;
};

float 
cMinBonus::Report(SyString *ans,float input)
{
  char buffer[256];
  float result = Apply(input);
  sprintf(buffer,"%d<%d=%d\t\t\t%s\n",(int)input,(int)mValue,(int)result,mName.AsChar());
  *ans+=buffer;
  return result;
}

//------------------------------------ cMaxBonus

float 
cMaxBonus::Apply(float input) 
{
  if (input > mValue)
  {
    return mValue;
  }
  return input;
};

float
cMaxBonus::Report(SyString *ans,float input)
{
  char buffer[256];
  float result = Apply(input);
  sprintf(buffer,"%d>%d=%d\t\t\t%s\n",(int)input,(int)mValue,(int)result,mName.AsChar());
  *ans+=buffer;
  return result;
}

//------------------------------------ cCalculation

cCalculation::cCalculation() 
: mTotal(0), mCalculated(false)
{
}

cCalculation::~cCalculation()
{
  std::vector<cBonus *>::iterator iter;
  for (iter = mBonuses.begin();iter != mBonuses.end();iter++)
  {
    delete *iter;
  }
}

void 
cCalculation::Add(int amount, const SyString &description)
{
  cAddBonus *bonus = new cAddBonus((float)amount,description);
  mBonuses.push_back(bonus);
  mCalculated = false;
}

void 
cCalculation::Multiply(float amount, const SyString &description)
{
  cMultiplyBonus *bonus = new cMultiplyBonus(amount,description);
  mBonuses.push_back(bonus);
  mCalculated = false;
}

void 
cCalculation::AddRandom(int min_amount,int max_amount, const SyString &description)
{
  cAddRandomBonus *bonus = new cAddRandomBonus(min_amount,max_amount,description);
  mBonuses.push_back(bonus);
  mCalculated = false;
}

void 
cCalculation::Set(int amount, const SyString &description)
{
  cSetBonus *bonus = new cSetBonus((float)amount,description);
  mBonuses.push_back(bonus);
  mCalculated = false;
}

void 
cCalculation::Min(int amount, const SyString &description)
{
  cMinBonus *bonus = new cMinBonus((float)amount,description);
  mBonuses.push_back(bonus);
  mCalculated = false;
}

void 
cCalculation::Max(int amount, const SyString &description)
{
  cMaxBonus *bonus = new cMaxBonus((float)amount,description);
  mBonuses.push_back(bonus);
  mCalculated = false;
}

int 
cCalculation::GetValue()
{
  if (!mCalculated)
  {
    mTotal = 0;

    int priority;
    for (priority = cBonus::PRIORITY_ADD; priority !=cBonus::NUM_PRIORITIES; priority++)
    {
      std::vector<cBonus *>::iterator iter;
      for (iter = mBonuses.begin();iter != mBonuses.end();iter++)
      {
        if ((*iter)->GetPriority() == priority)
        {
          mTotal = (*iter)->Apply(mTotal);
        }
      }
    }
    mCalculated = true;
  }
  return (int) mTotal;
}

void 
cCalculation::Report(SyString *ans)
{
  ans->Clear();
  int priority;
  float value = 0;
  for (priority = cBonus::PRIORITY_ADD; priority !=cBonus::NUM_PRIORITIES; ++priority)
  {
    std::vector<cBonus *>::iterator iter;
    for (iter = mBonuses.begin();iter != mBonuses.end();iter++)
    {
      if ((*iter)->GetPriority() == priority)
      {
        value = (*iter)->Report(ans,value);
      }
    }
  }
  char buffer[80];
  sprintf(buffer,"%d\tTotal\n",(int)value); 
  *ans += buffer;
}



// EOF
