import numpy as np  
  
from OptionContracts import *  
  
  
class Error(Exception):  
    pass  
   
class PricerError(Error):  
    _PricerStr = ""  
    _Msg = ""  
    def __init__(self,  pricerStr,  msg):  
        self._PricerStr  =  pricerStr  
        self._Msg  =  msg  
  
  
class OptionPricer(object):  
    _pricerId = ""  
    _contractList = []  
    _PricingParameters = []  
      
    def __init__(self):  
        self._contractList = [ ]  
        self._PricingParameters = []  
          
      
    def SetPricerId(self, pricerId):  
        self._pricerId = pricerId  
      
    def SetPricingParameters(self, pricingParameters):  
        self._PricingParameters = pricingParameters  
      
    def Calculate(self):  
        for optionContract in self._contractList:  
            if isinstance(optionContract, OptionContract):  
                self.CalculateContract(optionContract)  
              
          
    def CalculateContract(self, optionContract):  
        pass  
  
    def SetPricerParameters(self):  
        pass  
      
    def AddContract(self, optionContract):  
        if not isinstance(optionContract, OptionContract):  
            raise PricerError("OptionPricer",  "Not a proper Option Contract")  
        self._contractList.append(optionContract)  
  
    def RemoveContract(self, optionContract):  
        if optionContract not in self._contractList:  
            raise PricerError("OptionPricer",  "Cannot remove contract,  it is not in the list")  
        else:  
            self._contractList.remove(optionContract)  
             
    def PrintSelf(self):  
        print self._pricerId  
        self._PricingParameters.printSelf()  
        for optionContract in self._contractList:  
            optionContract.printSelf()  
  
   
class PricingParameters:  
    _div = [[], []]  
    _r = 0  
    _T = 0  
    _S0 = 0  
    _r2 = [[], []]  
      
    _pvdividends = 0  
    _fvdividends = 0  
      
    def __init__(self, S0, T, r, divi = "", r2 = ""):  
        self._S0 = float(S0)  
        self._T = float(T)  
        self._r = float(r)  
        self._r2 = r2  
          
        #we don't store dividends past T  
        if (np.size(divi)>0 and divi[0][0]<T) :  
            lastdiv = np.nonzero(np.array(divi[0][:])<= T)[0][-1]  
            self._div[0] = divi[0][:lastdiv+1]          
            self._div[1] = divi[1][:lastdiv+1]  
              
        #for the two dividend handling methods we need present and forward value of the dividend      
        if np.size(self._div)>0:  
            for index, dv in enumerate(list(self._div[1])):  
                self._pvdividends = self._pvdividends+dv*np.exp(self._r*(-self._div[0][index]))  
                self._fvdividends = self._fvdividends+dv*np.exp(self._r*(self._T-self._div[0][index]))  
     
    def printSelf(self):       
        print "S0\tstock price at time 0:",  self._S0  
        print "r\tcontinuously compounded risk-free rate:",  self._r  
        print "T\ttime to maturity in trading years:",  self._T  
        print "D\tDividends:", self._div   
      