'''
Created on Mar 20, 2012
@author: Dilum Bandara
@version: 0.22
@license: Apache License v2.0

   Copyright 2012 H. M. N. Dilum Bandara and Anura P. Jayasumana, Colorado State
   University

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
'''

'''
Generate resources for testing & performance analysis
'''

import math
import sys
import random


def uniform(minAtt, maxAtt, resPerQue, numQue, fixedN, fd):
    '''
    Generate given number of resources -Use uniform distribution
    @param minAtt: Minimum attribute value  
    @param maxAtt: Maximum attribute value
    @param resPerQue: Resources per query 
    @param numQue: Number of queries to generate
    @param fixedN: No of resources per query is fixed 
    @param fd: File descripter
    '''
    for i in range(numQue):
        tmpStr = 'n\t'
        if fixedN == True: tmpStr += str(resPerQue) + '\t'
        else: tmpStr += str(random.randint(1, resPerQue)) + '\t'
        value1 = random.randint(minAtt, maxAtt)
        value2 = random.randint(minAtt, maxAtt)
        if value1 < value2:
            tmpStr += 'cusAtt\t' + str(value1) + '\t' + str(value2) + '\n'
        else: tmpStr += 'cusAtt\t' + str(value2) + '\t' + str(value1) + '\n'
        fd.write(tmpStr)


def shuffle(queries):
    '''
    Shuffle queries based on Fisher-Yates shuffle. List is modified in place
    @param queries: List of queries
    '''
    for i in reversed(range(1, len(queries))):
        j = random.randrange(i + 1)
        queries[i], queries[j] = queries[j], queries[i]


def zipfs(alpha, keyFile, resPerQue, numQue, fixedN, fd):
    '''
    Generate queries according to a Zipf's distribution & dump both resources & 
    distinct keys into files. Each key is 32'bit logn
    @param alpha: Zipf's parameter
    @param keyFile: Name for key file
    @param resPerQue: Resources per query 
    @param numQue: Number of queries to generate
    @param fixedN: No of resources per query is fixed 
    @param fd: File descripter    
    '''
    keys = []
    fdKeys = open(keyFile, 'r')
    for line in fdKeys: keys.append(line.rstrip('\r\n')) 
    fdKeys.close()
    shuffle(keys) #shuffle keys
    
    denom = 0.0
    for i in range(len(keys)):
        denom += 1/math.pow(i + 1, alpha)

    numGenQue = 0
    que = []
    for i in range(len(keys)):
        num = int(math.ceil(((1/math.pow(i + 1, alpha))/denom) * numQue))
        numGenQue += num
        for j in range(num):
            tmpStr = 'n\t'
            if fixedN == True: tmpStr += str(resPerQue) + '\t'
            else: tmpStr += str(random.randint(1, resPerQue)) + '\t'
            tmpStr += 'cusAtt\t' + keys[i] + '\t' + keys[i] + '\n'
            que.append(tmpStr)
    shuffle(que) #shuffle queries
    for i in que: fd.write(i)
    
    print 'Total keys:', len(keys)
    print 'Total no of queries:', numGenQue
    frac = ((1/pow((1), alpha))/denom)
    print 'Most popular key has: ' + str(frac * 100) + '% ' + \
                            str(math.ceil(frac * numQue)) + ' Key is ' + keys[0]  


def cpuSpeed(resPerQue, numQue, fixedN, randomFraction, fd):
    '''
    Generate queries based on SWORD queries
    @param resPerQue: Resources per query 
    @param numQue: Number of queries to generate
    @param fixedN: No of resources per query is fixed
    @param randomFraction: What fraction of queries to be randomly generated  
    @param fd: File descripter
    '''
    rangeCSp = [[4, 0.0, 1.0], [4, 0.0, 6.0], [6, 0.5, 5.0], [1, 1.0, 6.0], \
                [5, 1.0, 5.0], [55, 2.0, 6.0], [3, 2.0, 5.0], [1, 0.0, 3.0]]
    totalEntries = 0
    for i in range(len(rangeCSp)):
        totalEntries += rangeCSp[i][0] 

    totalEntries += int((totalEntries * randomFraction))
    numEntreis = len(rangeCSp)
    for i in range(numQue):
        tmpStr = 'n\t'
        if fixedN == True: tmpStr += str(resPerQue) + '\t'
        else: tmpStr += str(random.randint(1, resPerQue)) + '\t'

        idx = random.randint(1, totalEntries)
        count = 0
        for j in range(numEntreis):
            if j == (numEntreis - 1):
                value1 = round(random.random() * 6.0, 1)
                value2 = round(random.random() * 6.0, 1)
                if value1 < value2:
                    tmpStr += 'CSp\t' + str(value1) + '\t' + str(value2) + '\n'
                else: tmpStr += 'CSp\t' + str(value2) + '\t' + str(value1) + '\n'
            else: 
                count += rangeCSp[j][0]
                if idx <= count:
                    tmpStr += 'CSp\t' + str(rangeCSp[j][1]) + '\t' + \
                                                str(rangeCSp[j][2]) + '\n'
                    break
        fd.write(tmpStr)


def main(*argv):
    '''
    Main function to indicate start of program
    '''
    baseFName = 'queries_'
    assert(len(sys.argv) == 2), \
        'Wrong parameters. Use \'python genQueries.py [seed]\''
    random.seed(int(sys.argv[1])) #Set seed
    fdOut = open(baseFName + sys.argv[1] + '.txt', 'w')
    
    #uniform(0, 1000, 6, 1000, False, fdOut)
    #Zipfs(1.0, 'keys.txt', 1, 100000, True, fdOut)
    cpuSpeed(5, 1000000, True, 0.1, fdOut)
    fdOut.close()


if __name__ == '__main__':
    sys.exit(main(*sys.argv))
