'''
Created on Sep 29, 2012

@author: elnio
'''

from __future__ import division
import Global as gl
import numpy as np
from numpy.ma.core import floor
from numpy.lib.scimath import sqrt
import scipy.stats as spStats
import copy as cp

class Grid:
    f = None
    c = None
    N = None
    R = None
    gn = None
    fgn = None
    factor = None
    threshold = None
    squnit = None
    unit = None
    punit = None
    unit_r = None
    p = None
    pp = None
    gridArray = None
    neigbors= None
    hitsL2 = None
    whole = None

    def __init__(self, correlation, c_para, f_para):
        self.whole = sqrt(gl.sw)
        self.f = f_para
        self.c = c_para*c_para
        self.N = gl.sw
        self.R = 2
        self.gn = floor(gl.numSketch/self.R)
        self.fgn = floor(self.f*self.gn)     
        self.factor= 2*self.c
        self.threshold = correlation 
        self.squnit=self.factor*2*(1-self.threshold)
        self.unit=sqrt(self.squnit)
        self.unit_r = 1/self.unit
        self.punit = sqrt(2*(1-self.threshold))
        self.p = 2*(1+ floor(self.whole/self.unit) )
        self.pp = floor( self.p/2)
        self.gridArray = np.empty(int(self.gn),dtype=object)
        
        for i in range(int(self.gn) ):
            gridd = np.empty(self.p*self.p,dtype=object)
            for j in range( int(self.p*self.p) ) :
                gridd[j] = [-1]
            gridd = np.reshape(gridd, (self.p, self.p) ) 
            self.gridArray[i] = gridd           
        self.gridArray_bk = cp.deepcopy( self.gridArray )
        self.hitsL2 = np.empty( gl.n_stream, dtype=object )
        np.ndarray.fill(self.hitsL2,[])
        
    def findNeighbor(self,x):
        if(x>0):
            a=np.array([x-1,x])
        else:
            a=np.array([x])
            
        if(x<(self.p-1)):
            a=np.append(a,x+1)
        return a
    
    def computNeighbor(self):
        self.neigbors=np.array([ [np.transpose([np.repeat(self.findNeighbor(i), len(self.findNeighbor(j))),
                                   np.tile(self.findNeighbor(j), len(self.findNeighbor(i)))])
                    for j in range(int(self.p)) ]
                    for i in range(int(self.p)) ])
    
    def redreshGrid(self):
        self.gridArray = cp.deepcopy(self.gridArray_bk)
        
    def hash(self, val):
        # return self.pp + np.floor(np.real(self.unit_r*val)) 
        val = val.real
        return self.pp + floor(self.unit_r*val)

    def blockChecker(self, gridInd ,indexNN):
        gr = self.gridArray[gridInd]
        dataCollect=[]
        for i in range( len(indexNN)):
            dataCollect+=( gr[   indexNN[i,0] , indexNN[i,1]  ]  )        
        dataCollect= np.array(dataCollect)
        return dataCollect[ np.nonzero(dataCollect>-1) ] #no prob to check if the returned length is
                                                        # greater than zero -- empty array.
          
    def distributeQuery(self, numExist, index, currTime):
        counter = np.zeros(numExist)    
        hashed = self.hash(gl.data[index].sketches)
        for i in range( int(self.gn) ):
            indexNN=self.neigbors[hashed[self.R*i],hashed[1+self.R*i]]
            dataCollect = self.blockChecker(i, indexNN)
            counter[ dataCollect ] +=1
            gridi = hashed[i*2]
            gridj = hashed[1+i*2]
            self.gridArray[i][gridi][gridj].append(index)
            
        nnlist = np.nonzero( (~(counter<self.fgn)) == True )  

        # compute positive correlation
        for i in range( len(nnlist[0]) ):
            index2 = int(nnlist[0][i])            
            if(index == index2):
                continue
            seriesLength = len(gl.data[index].series)
            assert seriesLength ==len(gl.data[index2].series), "Time series lengths are not the same"

            cor= spStats.pearsonr(gl.data[index].series,gl.data[index2].series)[0]            
            #Report the true positive
            if( cor >= self.threshold ):
                gl.outputFile.writerow([index,index2,currTime,currTime+gl.sw,cor])
                print "Time series %d and %d are have correlation of %.10f" %(index, index2, cor)
                self.hitsL2[index].append(index2)
                
        # compute negative correlation
        counter = np.zeros(numExist)
        hashed = self.hash(-gl.data[index].sketches)
        for i in range( int(self.gn) ):
            indexNN=self.neigbors[hashed[self.R*i],hashed[1+self.R*i]]
            dataCollect = self.blockChecker(i, indexNN)
            counter[ dataCollect ] +=1
        nnlist = np.nonzero( (~(counter<self.fgn)) == True )
        for i in range( len(nnlist[0]) ):
            index2 = int(nnlist[0][i])
            if(index == index2):
                continue
            seriesLength = len(gl.data[index].series)
            assert seriesLength ==len(gl.data[index2].series), "Time series lengths are not the same"
        
            cor= spStats.pearsonr(gl.data[index].series,gl.data[index2].series)[0]            
            #Report true negative
            if( cor < -self.threshold):
                gl.outputFile.writerow([index,index2,currTime,currTime+gl.sw,cor])
                print "Time series %d and %d are have correlation of %.10f" %(index, index2, cor)
                self.hitsL2[index].append(index2) 
        