"""
    A StretchFile reads disk files into RAM and creates Record objects from their contents.
"""
import GeoIP
import abc
import os
import os.path
#from os.path import isfile
import re

from pogo.dto.record import LogRecord, AttemptRecord, SessionLogRecord, SessionDownloadFileRecord
from pogo.dto.record import SessionRecordingRecord
from pogo.util.util import get_geo_info

class StretchFile(object):
    __metaclass__ = abc.ABCMeta
    def __init__(self, file_name):
        self._name = file_name
        self._entry_list = []
        self._loaded = False
    
    def name(self):
        return self._name
    
    def __iter__(self):
        return iter(self._entry_list)
    
    # override __len__ so that len(bungeedatafile)
    # returns the number of files in entry_list
    def __len__(self):
        return len(self._entry_list)
    
    @abc.abstractmethod
    def load(self):
        pass


class AttemptFile(StretchFile):
    def __init__(self, file_name):
        super(AttemptFile, self).__init__(file_name)

    def load(self):
        if os.path.isfile(self.name()):
            try:
                f = open(self.name(), "rt")
                try:
                    for line in f:
                        r = AttemptRecord(line.rstrip())
                        self._entry_list.append(r)
                    f.close()
                    self._loaded = True
                    return True
                except IOError:
                    if f is not None:
                        f.close()
                    logging.error("Failed to load file ", exc_info = True)
                    print "During loading of " + self.name() + " encountered i/o error reading line " + line
                    self._loaded = False
                    return False
            except IOError:
                logging.error("Could not open file", exc_info = True)
                self._loaded = False
                return False
        else: 
            raise ValueError(self.name() + " is not a file.")
            self._loaded = False
            return False
    

class LogFile(StretchFile):
    EXTRA_LINE_PATTERN = re.compile('^\t')

    def __init__(self, file_name):
        super(LogFile, self).__init__(file_name)
        
    def load(self):
        if os.path.isfile(self.name()):
            try:
                f = open(self.name(), "rt")
                try:
                    for line in f:
                        if LogFile.EXTRA_LINE_PATTERN.match(line):
                            # Don't use this to construct a
                            # LogRecord. Instead, tack it on to
                            # the end of the last entry's message
                            # field.
                            if len(self._entry_list) > 0:
                                r = self._entry_list.pop()
                                r.message += ' -- ' + line.strip()
                        else:
                            r = LogRecord(line.rstrip()) 
                        self._entry_list.append(r)
                        
                    f.close()
                    self._loaded = True
                    return True
                except IOError:
                    if f is not None:
                        f.close()
                    logging.error("Could not read a line in file", exc_info = True)    
                    print "During loading of " + self.name() + " encountered i/o error reading line " + line
                    self._loaded = False
                    return False
            except IOError:
                logging.error("Failed to load file ", exc_info = True)
                print "Error during loading of file " + self.name()
                self._loaded = False
                return False
        else: 
            raise ValueError(self.name() + " is not a file.")
            self._loaded = False
            return False
# end of LogFile.load())


class SessionLogFile(StretchFile):
    def __init__(self, file_name):
        super(SessionLogFile, self).__init__(file_name)
        # Get second-to-last element of filespec -- this is the IP address
        source_ip = file_name.split(os.sep)[-2]
        self.set_source_ip(source_ip)
        
    def set_source_ip(self, source_ip):
        if source_ip:
            self.source_ip = source_ip
            gpi = get_geo_info(self.source_ip)
            self.country_code = gpi.country_code
            self.country_name = gpi.country_name
        else:
            self.source_ip = ''
            self.country_code = ''
            self.country_name = ''

        
    def load(self):
        if os.path.isfile(self.name()):
            try:
                f = open(self.name(), "rt")
                try:
                    for line in f:
                        r = SessionLogRecord(line)
                        r.set_source_ip(self.source_ip)
                        r.set_country_info(self.country_code, self.country_name)
                        self._entry_list.append(r)
                    f.close()
                    self._loaded = True
                    return True
                except IOError:
                    if f is not None:
                        f.close()
                        logging.error("Failed to load file ", exc_info = True)
                        print "During loading of " + self.name() + " encountered i/o error reading line " + line
                    self._loaded = False
                    return False
            except IOError:
                logging.error("Failed to load file ", exc_info = True)
                print "Error during loading of file " + self.name()
                self._loaded = False
                return False
        else: 
            raise ValueError(self.name() + " is not a file.")
            self._loaded = False
            return False
# end of SessionLogFile.load())


class SessionDownloadFile(StretchFile):
    def __init__(self, file_name):
        super(SessionDownloadFile, self).__init__(file_name)
        # IP is third-to-last element of filespec
        source_ip = file_name.split(os.sep)[-3]
        self.set_source_ip(source_ip)
        
    def set_source_ip(self, source_ip):
        if source_ip:
            self.source_ip = source_ip
            gpi = get_geo_info(self.source_ip)
            self.country_code = gpi.country_code
            self.country_name = gpi.country_name
        else:
            self.source_ip = ''
            self.country_code = ''
            self.country_name = ''

        
    def load(self):
        if os.path.isfile(self.name()):
            try:
                with open(self.name(), "rb") as f:
                    data = f.read()
                    if data:
                        data64 = data.encode("base64")
                    else:
                        data64 = ''
                    r = SessionDownloadFileRecord(self.name(), data64)
                    # Part of file name is a datetime stamp. Extract it
                    namepart = self.name().split(os.sep)[-1] # get last element of filespec
                    # datetime string in format expected by set_timestamp():
                    normalized_namepart = ( namepart[0:4] + '-'
                                             + namepart[4:6] + '-'
                                             + namepart[6:8] + ' '
                                             + namepart[9:11] + ':'
                                             + namepart[11:13] + ':'
                                             + namepart[13:15] )
                    r.set_timestamp(normalized_namepart)
                    r.set_source_ip(self.source_ip)
                    r.set_country_info(self.country_code, self.country_name)
                    self._entry_list.append(r)
                    self._loaded = True
                    return True
            except IOError:
                logging.error("Failed to load file ", exc_info = True)
                print "During loading of " + self.name() + " encountered i/o error"
                self._loaded = False
                return False
        else: 
            raise ValueError(self.name() + " is not a file.")
            self._loaded = False
            return False
# end of SessionDownloadFile.load())


class SessionRecordingFile(StretchFile):
    def __init__(self, file_name):
        super(SessionRecordingFile, self).__init__(file_name)
        # IP is second-to-last element of filespec
        source_ip = file_name.split(os.sep)[-2]
        self.set_source_ip(source_ip)
        
    def set_source_ip(self, source_ip):
        if source_ip:
            self.source_ip = source_ip
            gpi = get_geo_info(self.source_ip)
            self.country_code = gpi.country_code
            self.country_name = gpi.country_name
        else:
            self.source_ip = ''
            self.country_code = ''
            self.country_name = ''

        
    def load(self):
        if os.path.isfile(self.name()):
            try:
                with open(self.name(), "rb") as f:
                    data = f.read()
                    if data:
                        data64 = data.encode("base64")
                    else:
                        data64 = ''
                    r = SessionRecordingRecord(self.name(), data64)
                    # Part of file name is a datetime stamp. Extract it
                    namepart = self.name().split(os.sep)[-1] # get last element of filespec
                    # datetime string in format expected by set_timestamp():
                    normalized_namepart = ( namepart[0:4] + '-'
                                             + namepart[4:6] + '-'
                                             + namepart[6:8] + ' '
                                             + namepart[9:11] + ':'
                                             + namepart[11:13] + ':'
                                             + namepart[13:15] )
                    r.set_timestamp(normalized_namepart)
                    r.set_source_ip(self.source_ip)
                    r.set_country_info(self.country_code, self.country_name)
                    self._entry_list.append(r)
                    self._loaded = True
                    return True
            except IOError:
                logging.error("Failed to load file ", exc_info = True)
                print "During loading of " + self.name() + " encountered i/o error"
                self._loaded = False
                return False
        else: 
            raise ValueError(self.name() + " is not a file.")
            self._loaded = False
            return False
# end of SessionRecordingFile.load())



