'''
Created on Jan 13, 2012

@author: mao


Enviar times com print. Depois e' redireccionado para um ficheiro no JDL.
'''
from __future__ import division
import os
import sys
import urllib2
import zipfile
import datetime
from time import ctime
import ntplib
import platform

PYTHON_REQUIRED_VERSION = (2,2)
PYTHON_CURRENT_VERSION = sys.version_info
MASK = 65535 #int('1111111111111111',2) #0b1111111111111111
BIL_EXTENSION = ".bil"
HDR_EXTENSION = ".hdr"
ZIP_EXTENSION = ".zip"
CSV_EXTENSION = ".csv"

def readHeaderFile(name):
    '''
    Reads the hdr file of the BIL format and returns the values as a dictionary.
    '''
    fp = open(name+'.hdr', 'r')
    dados = list()
    for linha in fp.readlines():
        linha = linha.strip()
        index = linha.find(' ')
        if (index <> -1):
            key = linha[:index]
            value = linha[index:].strip()
            dados.append((key,value))
    fp.close()
    dictionary = dict(dados)
    return dictionary

def getValueFromSignedBinary(binary):
    '''
    Returns the integer representation of a signed binary number as a String in the form of '0b0000000000000000
    First thing to do is to check if its 16 bits or not
    '''
    if binary.startswith('0b'):
        #value = int(binary,2) #Em 2.4.3 esta a dar erro no int.
        value = integerValue(binary) 
        if (len(binary[2:])==16):
            signal = binary[2:3]
            if (signal == '1'): value = - ((value ^ MASK) + 1)
        return value
    return

def integerValue(binaryValue):
    '''
    Converts a binary value to its integer 
    '''
    ordValue = 0
    order = 0
    binValue = binaryValue [2:]
    for i in range(-1, -(len(binValue)+1), -1):
        ordValue = ordValue + (int(binValue[i]) * (2 ** order))
        order +=1 
    return ordValue
    

def binaryValue(ordinalValue):
    ''' Converts an ordinal number to its binary representation '''
    binValue = ''
    tempValue = ordinalValue
    rest = 0
    while tempValue != 1 and tempValue != 0:
        rest = tempValue % 2
        tempValue = tempValue // 2
        binValue = str(rest) + binValue
    else:
        binValue = str(tempValue) + binValue
    return binValue

def readfile_byte(name):
    time_1 = datetime.datetime.now()
    print "CONVERSION started at %s " % time_1.isoformat()
    dictionary = readHeaderFile(name)
    NCOLS = int(dictionary['NCOLS'])
    NROWS = int(dictionary['NROWS'])
    minValue = int(dictionary['MinValue'])
    maxValue = int(dictionary['MaxValue'])
    fp = open(name+BIL_EXTENSION, 'rb')
    fw = open(name+CSV_EXTENSION, 'w')
    #fpWrapper = codecs.EncodedFile(fp, 'ascii', 'utf-16')
    _byte1 = fp.read(1)
    _byte2 = fp.read(1)
    _line= 1
    _col = 0
    while _byte1 != None and _line <= NROWS:
        _col += 1
        try: 
            #secondByte = str(bin(ord(_byte1))[2:]) #Em 2.4.3 esta a dar erro no bin.
            #firstByte = str(bin(ord(_byte2))[2:])
            secondByte = binaryValue(ord(_byte1))
            firstByte = binaryValue(ord(_byte2))
            if len(firstByte) < 8:
                firstByte = '0'*(8-len(firstByte))+firstByte
            if len(secondByte) < 8:
                secondByte = '0'*(8-len(secondByte))+secondByte
            bin_str = '0b'+firstByte+secondByte
            value = getValueFromSignedBinary(bin_str)
            if (value <> -9999):
                if (value > maxValue or value < minValue):
                    print "Esperava valores entre %d e %d. Obtive %d na linha %s e coluna %s do ficheiro %s, com os valores lidos %s e %s" % (minValue, maxValue, value, _line, _col, name, firstByte, secondByte)
                value = value/10.0
                fw.write('%.2f'% value)
            else:
                fw.write('%d' % value)
            #print ("%s, %s: %.2f") % (_line, _col, value)
        except ValueError:
            print "ValueError on string at %s, %s, and text %s" % (_line, _col,_byte2) 
        except TypeError:
            print "TypeError on string at %s, %s." % (_line, _col)
        if _col == NCOLS:
            _col = 0
            _line += 1
            fw.write(os.linesep)
        else:
            fw.write(',')
        #print (int(str(bin(ord(_bit1))[2:] + bin(ord(_bit2))[2:]),2))
        #print(str(_line) + ' ' + unichr(int(_bit)))
        _byte1 = fp.read(1)
        _byte2 = fp.read(1)
    fp.close()
    fw.close()
    time_2 = datetime.datetime.now()
    print "CONVERSION ended at %s " % time_2.isoformat()
    convertElapsedTime = time_2 - time_1
    print "CONVERSION of file %s, took %d seconds and %d microseconds" % (name + BIL_EXTENSION, convertElapsedTime.seconds, convertElapsedTime.microseconds)

def unzip(name):
    time_1 = datetime.datetime.now()
    print "UNZIP started at %s " % time_1.isoformat()
    zf = zipfile.ZipFile(name + ZIP_EXTENSION, 'r')
    namesList = list()
    for filename in zf.namelist():
        mode = 'w'
        if filename.endswith(BIL_EXTENSION):
            namesList.append(filename[:-len(BIL_EXTENSION)])
            mode = 'wb'
        #inputFile = zf.open(filename) #Works with 2.6binaryV
        output = open(filename,mode)
        #output.write(inputFile.read()) #Works with 2.6
        output.write(zf.read(filename)) #Works with 2.2
        output.close()
        #inputFile.close() #Works with 2.6
    time_2 = datetime.datetime.now()
    print "UNZIP ended at %s " % time_2.isoformat()
    unzipElapsedTime = time_2 - time_1
    print "unzip of file %s, took %d seconds and %d microseconds" % (name + ZIP_EXTENSION, unzipElapsedTime.seconds, unzipElapsedTime.microseconds)
    for fname in namesList:
        readfile_byte(fname)

def downloadFile(address, name):
    time_1 = datetime.datetime.now()
    print "DOWNLOAD started at %s " % time_1.isoformat()
    zipFile = urllib2.urlopen(address + name + ZIP_EXTENSION)
    output = open(name + ZIP_EXTENSION,'wb')
    output.write(zipFile.read())
    output.close()
    time_2 = datetime.datetime.now()
    print "DOWNLOAD ended at %s " % time_2.isoformat()
    stats = os.stat(name+ZIP_EXTENSION)
    downloadAndWriteElapsedTime = time_2 - time_1
    print "Download of file %s (%d bytes), took %d seconds and %d microseconds" % (name + ZIP_EXTENSION, stats.st_size, downloadAndWriteElapsedTime.seconds, downloadAndWriteElapsedTime.microseconds)
    unzip(name)
    
if __name__ == '__main__':
    if (len(sys.argv) == 3 and PYTHON_CURRENT_VERSION >= PYTHON_REQUIRED_VERSION):
        ntpClient = ntplib.NTPClient()
        ntpResponse = ntpClient.request('0.rhel.pool.ntp.org', version=3)
        print "NTP reference time %s " % ctime(ntpResponse.recv_time)
        print "NTP offset %f " % ntpResponse.offset
        time_start = datetime.datetime.now()
        print "APP started at %s " % time_start.isoformat()
        downloadFile(sys.argv[1], sys.argv[2])
        time_end = datetime.datetime.now()
        print "APP ended at %s " % time_end.isoformat()
        appElapsedTime = time_end - time_start
        print "App took %d seconds and %d microseconds" % (appElapsedTime.seconds, appElapsedTime.microseconds)
        
    else:
        print "Usage: python IO.py <address> <filename>"
        print "Downloads <address><filename>.zip"
        print "Unzips the downloaded file"
        print "processes all unzipped bil files generating a csv file for each input."
        print "Python version 2.2 or higher required."
        if (PYTHON_CURRENT_VERSION < PYTHON_REQUIRED_VERSION):
            print "Python version " + platform.python_version() + " found, please consider upgrading. :)"
            
            
            
