# -*- coding: utf-8 -*-
'''
Created on Jan 31, 2013

@author: ymh
'''

from ..utils import show_progress
from django.core.management.base import BaseCommand
from django.db import transaction
from egonomy.models import ImageMetadata
from optparse import make_option
import csv
import sys
import datetime


class Command(BaseCommand):
    '''
    Import Pertimm csv files
    '''

    args = 'csv_file csv_file ...'
    help = 'Import Pertimm csv files'
    
    option_list = BaseCommand.option_list + (
        make_option('-n', '--max-lines',
            dest= 'max_lines',
            type='int',
            default= sys.maxint,
            help= 'max number of line to process, -1 process all file' 
        ),
        make_option('-b', '--batch-size',
            dest= 'batch_size',
            type='int',
            default= 5000,
            help= 'number of object to import in bulk operations' 
        ),
        make_option('-e', '--encoding',
            dest= 'encoding',
            default= 'utf8',
            help= 'csv files encoding' 
        ),
        make_option('--skip',
            dest= 'skip',
            type='int',
            default= 0,
            help= 'number of entry to skip' 
        ),
        make_option('--stop',
            dest= 'cont',
            action= 'store_false',
            default= True,
            help= 'stop on error' 
        ),
        make_option('-l', '--log',
            dest= 'log',
            default= 'log.txt',
            help= 'log file' 
        ),
    )
    
    def __safe_get(self, dict_arg, key, conv = lambda x: x, default= None):
        val = dict_arg.get(key, default)
        return conv(val) if val else default

    def __safe_decode(self, s):
        if not isinstance(s, basestring):
            return s
        try:
            return s.decode('utf8')
        except:
            try:
                return s.decode('latin1')
            except:
                return s.decode('utf8','replace')

    def handle(self, *args, **options):
                
        max_lines = options.get('max_lines', sys.maxint)
        csv_files_dialect = {}
        skip = options.get('skip', 0)
        # calculating the number of lines to process
        print("calculating number of line to process")
        total = 0
        for csv_file_path in args:            
            with open(csv_file_path,'rb') as csv_file:
                dialect = csv.Sniffer().sniff(csv_file.read(1024))
                dialect.doublequote = True
                csv_files_dialect[csv_file_path] = dialect
                csv_file.seek(0)
                for _ in csv.DictReader(csv_file, dialect=dialect):
                    total += 1
                    if total > max_lines:
                        break
        
        nb_lines = min(max_lines, total)
        batch_size = options.get('batch_size', 5000)
        
        print("There is %d lines to process, starting processing now." % nb_lines)
        counter = 0
        writer = None
        encoding = options.get('encoding', 'utf8')
        log_path = options.get('log', "log.txt")
        cont_on_error = options.get('cont', True)

        transaction.enter_transaction_management()
        transaction.managed()
        try:        
            for csv_file_path in args:
                with open(csv_file_path,'rb') as csv_file:
                    dialect = csv_files_dialect.get(csv_file_path,None)
                    if not dialect:
                        dialect = csv.Sniffer().sniff(csv_file.read(1024))
                        dialect.doublequote = True
                        csv_file.seek(0)
                    
                    dictreader = csv.DictReader(csv_file, dialect=dialect)
                    thesaurus_fields = sorted([fname for fname in dictreader.fieldnames if fname.startswith("THESAURUS")], key=lambda name: int(name[len("THESAURUS_"):]))
                                        
                    for row in dictreader:
                        try:
                            counter += 1
                            if counter <= skip:
                                continue
                            if counter > nb_lines:
                                break
                            urow = dict([(k, v.decode(encoding, 'replace') if v else v) for k,v in row.items()])
                            writer = show_progress(counter, nb_lines, u"%s - %s - %d/%d" % (urow['CLICHE'], urow['TITRE'], counter%batch_size, batch_size), 80, writer)
                                                                                        
                            img_id = urow['CLICHE']
                            
                            thesaurus_pertimm = "|".join([urow[fname] for fname in thesaurus_fields if urow[fname]])
                                                        
                            ImageMetadata.objects.filter(id=img_id).update(titre_pertimm=urow["PERTIMM_TITRE"], description_pertimm=urow["PERTIMM_DESCRIPTION"], thesaurus_pertimm=thesaurus_pertimm)
                            
                        except Exception as e:                            
                            error_msg = "%s - Error treating line %d, file %s local %d : id %s - title : %s : %s\n" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),counter, csv_file_path, dictreader.line_num, row['CLICHE'] if (row and 'CLICHE' in row and row['CLICHE']) else 'n/a', row['TITRE'] if (row and 'TITRE' in row and row['TITRE']) else 'n/a', repr(e) )
                            with open(log_path, 'a') as log_file:
                                log_file.write(error_msg)
                            if not cont_on_error:
                                raise
                        
                        
                        if not (counter%batch_size):
                            transaction.commit()
                            
                        
                if counter > nb_lines:
                    break
            
            transaction.commit()        
        except:
            transaction.rollback()            
            raise
        finally:
            transaction.leave_transaction_management()
            