# Copyright (C) University of Tennessee Health Science Center, Memphis, TN.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# This program is available from Source Forge: at GeneNetwork Project
# (sourceforge.net/projects/genenetwork/).
#
# Contact Drs. Robert W. Williams and Xiaodong Zhou (2010)
# at rwilliams@uthsc.edu and xzhou15@uthsc.edu
#
#
#
# This module is used by GeneNetwork project (www.genenetwork.org)
#
# Created by GeneNetwork Core Team 2010/08/10
#
# Last updated by GeneNetwork Core Team 2010/10/20

#from mod_python import Cookie
import string
import os

import reaper

import webqtlConfig
import cookieData
import sessionData
from cgiData import cgiData
from webqtlCaseData import webqtlCaseData
from utility import webqtlUtil



class webqtlFormData:
    'Represents data from a WebQTL form page, needed to generate the next page'
    attrs = ('formID','RISet','genotype','strainlist','allstrainlist',
    'suggestive','significance','submitID','identification', 'enablevariance',
    'nperm','nboot','email','incparentsf1','genotype_1','genotype_2','traitInfo')

    #XZ: Attention! All attribute values must be picklable!

    def __init__(self, start_vars = None, req = None, mod_python_session=None, FieldStorage_formdata=None):

        self.__dict__.update(start_vars)

        for item in self.attrs:
            setattr(self,item, None)

        try:
            self.remote_ip = req.connection.remote_ip
        except:
            self.remote_ip = '1.2.3.4'

        if req and req.headers_in.has_key('referer'):
            self.refURL = req.headers_in['referer']
        else:
            self.refURL = None

        # For now let's just comment all this out - Sam

        #self.cookies = cookieData.cookieData(Cookie.get_cookies(req)) #XZ: dictionary type. To hold values transfered from mod_python Cookie.
        #
        ##XZ: dictionary type. To hold values transfered from mod_python Session object. We assume that it is always picklable.
        #self.input_session_data = sessionData.sessionData( mod_python_session )
        #
        ##XZ: FieldStorage_formdata may contain item that can't be pickled. Must convert to picklable data.
        #self.formdata = cgiData( FieldStorage_formdata )
        #
        ##get Form ID
        #self.formID = self.formdata.getfirst('FormID')
        #
        ##get rest of the attributes
        #if self.formID:
        #       for item in self.attrs:
        #               value = self.formdata.getfirst(item)
        #               if value != None:
        #                       setattr(self,item,string.strip(value))

        self.ppolar = ""
        self.mpolar     = ""
        if self.RISet:
            try:
                # NL, 07/27/2010. ParInfo has been moved from webqtlForm.py to webqtlUtil.py;
                f1, f12, self.mpolar, self.ppolar = webqtlUtil.ParInfo[self.RISet]
            except:
                f1 = f12 = self.mpolar = self.ppolar = None

        try:
            self.nperm = int(self.nperm)
            self.nboot = int(self.nboot)
        except:
            self.nperm = 2000 #XZ: Rob asked to change the default value to 2000
            self.nboot = 2000 #XZ: Rob asked to change the default value to 2000

        if self.allstrainlist:
            self.allstrainlist = map(string.strip, string.split(self.allstrainlist))
        #self.readGenotype()
        #self.readData()

        if self.RISet == 'BXD300':
            self.RISet = 'BXD'
        else:
            pass

    def __getitem__(self, key):
        return self.__dict__[key]

    def get(self, key, default=None):
        if key in self.__dict__:
            return self.__dict__[key]
        else:
            return default

    def __str__(self):
        rstr = ''
        for item in self.attrs:
            if item != 'genotype':
                rstr += '%s:%s\n' % (item,str(getattr(self,item)))
        return rstr


    def readGenotype(self):
        'read genotype from .geno file'
        if self.RISet == 'BXD300':
            self.RISet = 'BXD'
        else:
            pass
        assert  self.RISet
        #genotype_1 is Dataset Object without parents and f1
        #genotype_2 is Dataset Object with parents and f1 (not for intercross)
        self.genotype_1 = reaper.Dataset()
        self.genotype_1.read(os.path.join(webqtlConfig.GENODIR, self.RISet + '.geno'))
        try:
            # NL, 07/27/2010. ParInfo has been moved from webqtlForm.py to webqtlUtil.py;
            _f1, _f12, _mat, _pat = webqtlUtil.ParInfo[self.RISet]
        except:
            _f1 = _f12 = _mat = _pat = None

        self.genotype_2 =self.genotype_1
        if self.genotype_1.type == "riset" and _mat and _pat:
            self.genotype_2 = self.genotype_1.add(Mat=_mat, Pat=_pat)       #, F1=_f1)

        #determine default genotype object
        if self.incparentsf1 and self.genotype_1.type != "intercross":
            self.genotype = self.genotype_2
        else:
            self.incparentsf1 = 0
            self.genotype = self.genotype_1
        self.strainlist = list(self.genotype.prgy)
        self.f1list = self.parlist = []
        if _f1 and _f12:
            self.f1list = [_f1, _f12]
        if _mat and _pat:
            self.parlist = [_mat, _pat]

    def readData(self, strainlst=[], incf1=[]):
        'read user input data or from trait data and analysis form'

        if not self.genotype:
            self.readGenotype()
        if not strainlst:
            if incf1:
                strainlst = self.f1list + self.strainlist
            else:
                strainlst = self.strainlist


        traitfiledata = self.formdata.getfirst('traitfile')
        traitpastedata = self.formdata.getfirst('traitpaste')
        variancefiledata = self.formdata.getfirst('variancefile')
        variancepastedata = self.formdata.getfirst('variancepaste')
        Nfiledata = self.formdata.getfirst('Nfile')


        if traitfiledata:
            tt = string.split(traitfiledata)
            vals = map(webqtlUtil.StringAsFloat, tt)
        elif traitpastedata:
            tt = string.split(traitpastedata)
            vals = map(webqtlUtil.StringAsFloat, tt)
        else:
            vals = map(self.FormDataAsFloat, strainlst)

        if len(vals) < len(strainlst):
            vals += [None]*(len(strainlst) - len(vals))
        elif len(vals) > len(strainlst):
            vals = vals[:len(strainlst)]
        else:
            pass


        if variancefiledata:
            tt = string.split(variancefiledata)
            vars = map(webqtlUtil.StringAsFloat, tt)
        elif variancepastedata:
            tt = string.split(variancepastedata)
            vars = map(webqtlUtil.StringAsFloat, tt)
        else:
            vars = map(self.FormVarianceAsFloat, strainlst)

        if len(vars) < len(strainlst):
            vars += [None]*(len(strainlst) - len(vars))
        elif len(vars) > len(strainlst):
            vars = vars[:len(strainlst)]
        else:
            pass

        if Nfiledata:
            tt = string.split(Nfiledata)
            nstrains = map(webqtlUtil.IntAsFloat, tt)
            if len(nstrains) < len(strainlst):
                nstrains += [None]*(len(strainlst) - len(nstrains))
        else:
            nstrains = map(self.FormNAsFloat, strainlst)

        ##vals, vars, nstrains is obsolete
        self.allTraitData = {}
        for i, _strain in enumerate(strainlst):
            if vals[i] != None:
                self.allTraitData[_strain] = webqtlCaseData(vals[i], vars[i], nstrains[i])



    def informativeStrains(self, strainlst=[], incVars = 0):
        '''if readData was called, use this to output the informative strains
           (strain with values)'''
        if not strainlst:
            strainlst = self.strainlist
        strains = []
        vals = []
        vars = []
        for _strain in strainlst:
            if self.allTraitData.has_key(_strain):
                _val, _var = self.allTraitData[_strain].val, self.allTraitData[_strain].var
                if _val != None:
                    if incVars:
                        if _var != None:
                            strains.append(_strain)
                            vals.append(_val)
                            vars.append(_var)
                    else:
                        strains.append(_strain)
                        vals.append(_val)
                        vars.append(None)
        return strains, vals, vars, len(strains)



    def FormDataAsFloat(self, key):
        try:
            return float(self.formdata.getfirst(key))
        except:
            return None


    def FormVarianceAsFloat(self, key):
        try:
            return float(self.formdata.getfirst('V' + key))
        except:
            return None

    def FormNAsFloat(self, key):
        try:
            return int(self.formdata.getfirst('N' + key))
        except:
            return None

    def Sample(self):
        'Create some dummy data for testing'
        self.RISet = 'BXD'
        self.incparentsf1 = 'on'
        #self.display = 9.2
        #self.significance = 16.1
        self.readGenotype()
        self.identification = 'BXD : Coat color example by Lu Lu, et al'
        #self.readGenotype()
        #self.genotype.ReadMM('AXBXAforQTL')
        #self.strainlist = map((lambda x, y='': '%s%s' % (y,x)), self.genotype.prgy)
        #self.strainlist.sort()
        self.allTraitData = {'BXD29': webqtlCaseData(3), 'BXD28': webqtlCaseData(2),
        'BXD25': webqtlCaseData(2), 'BXD24': webqtlCaseData(2), 'BXD27': webqtlCaseData(2),
        'BXD21': webqtlCaseData(1), 'BXD20': webqtlCaseData(4), 'BXD23': webqtlCaseData(4),
        'BXD22': webqtlCaseData(3), 'BXD14': webqtlCaseData(4), 'BXD15': webqtlCaseData(2),
        'BXD16': webqtlCaseData(3), 'BXD11': webqtlCaseData(4), 'BXD12': webqtlCaseData(3),
        'BXD13': webqtlCaseData(2), 'BXD18': webqtlCaseData(3), 'BXD19': webqtlCaseData(3),
        'BXD38': webqtlCaseData(3), 'BXD39': webqtlCaseData(3), 'BXD36': webqtlCaseData(2),
        'BXD34': webqtlCaseData(4), 'BXD35': webqtlCaseData(4), 'BXD32': webqtlCaseData(4),
        'BXD33': webqtlCaseData(3), 'BXD30': webqtlCaseData(1), 'BXD31': webqtlCaseData(4),
        'DBA/2J': webqtlCaseData(1), 'BXD8': webqtlCaseData(3), 'BXD9': webqtlCaseData(1),
        'BXD6': webqtlCaseData(3), 'BXD5': webqtlCaseData(3), 'BXD2': webqtlCaseData(4),
        'BXD1': webqtlCaseData(1), 'C57BL/6J': webqtlCaseData(4), 'B6D2F1': webqtlCaseData(4),
        'BXD42': webqtlCaseData(4), 'BXD40': webqtlCaseData(3)}