# -*- coding: utf-8 -*-

from trac.core import *

from trac.util.datefmt import format_date, to_datetime
from trac.config import Option, ListOption

from trac.ticket.api import ITicketManipulator
from trac.ticket.model import Ticket


class ChangeDateRecordProvider(Component):
    implements(ITicketManipulator)
    #sample:'assigned:last_assigned, accepted, reopened, closed:last_closed'
    ListOption('changedaterecord', 'order', default='assigned, accepted, reopened, closed',
                       doc='status order')
    

    def validate_ticket(self, req, ticket):
        """If status changed, then set date to custom field."""
        status_dt = set_status(self.env, ticket.id,
                               ticket['status'], ticket['changetime'])
        
        #self.log.info("record date:" + status_dt)
        
        if ticket._old.has_key('status'):
            for field in status_dt:
                #チケットの登録、編集時に直接入力された場合はそちらを優先する
                if ticket._old.has_key(field) and ticket[field] != '':
                    continue
                ticket[field] = status_dt[field]
        
        return []

def get_custom_value(db, ticket_id, filed):
    cursor = db.cursor()
    cursor.execute("SELECT value from ticket_custom where ticket=%s"
                           " and name=%s", (ticket_id, filed))
    row = cursor.fetchone()
    if row and row[0] is not None and row[0].strip() != '':
        return row[0]
    
    return None
    
def set_status(env, ticket_id, new_status,
               new_time, db=None, reset=False):
    if not db:
        db = env.get_db_cnx()
        
    order, custom_fields = get_order(env)
    
    #new_statusの位置を保持しておく。ここに至るまでの
    #ステータスに対応するカスタムフィールドの値は変更しないように
    #するため
    try:
        new_status_index = order.index(new_status)
    except ValueError:
        #orderに定義がないステータスが設定された場合は何も変更しない
        return {}
        
    
    #カスタムフィールドに設定する日付
    #new_timeがNoneの場合(Webからの通常操作)、現在日付となる
    formated_date = format_date(to_datetime(new_time), format='%Y-%m-%d')
    
    result = {}
    for index, status in enumerate(order):
        if not status in custom_fields.keys():
            continue
        
        custom_filed = custom_fields[status]
        
        if index < new_status_index:
            #設定済みの値を削除する
            result[custom_filed] = ''
            continue
        
        if index >= new_status_index:
            #既に値が設定済みの場合、もしくは非リセットモード時は
            #上書きしない
            custom_filed_value = get_custom_value(db, ticket_id, custom_filed)
            if custom_filed_value is None or reset is True:
                result[custom_filed] = formated_date
        
    return result

def get_order(env):
    order_lst = env.config.getlist('changedaterecord', 'order')
    order = []
    custom_fields = {}
    for m in order_lst:
        ms = m.split(':')
        if len(ms) >= 2:
            order.append(ms[0])
            custom_fields[ms[0]] = ':'.join(ms[1:])
        else:
            order.append(m)
            
    order.reverse()
    return (order, custom_fields)

def reset_status(env, ticket_id, db=None):
    order, custom_fields = get_order(env)
    history = get_history(env, ticket_id, db)

    result = {}
    for status, time in history:
        status_dt = set_status(env, ticket_id, status, time, db, True)
        result.update(status_dt)
    
    return result

def get_history(env, ticket_id, db=None):
    if not db:
        db = env.get_db_cnx()

    cursor = db.cursor()
    
    history = []
    
    #チケット新規登録はticket_changeテーブルに記録されていないため、
    #historyにnewを追加しておく
    cursor.execute('SELECT time from ticket where id = %s', (ticket_id,))
    row = cursor.fetchone()
    history.append(('new', to_datetime(row[0])))

    #過去の変更履歴よりステータス名、変更時間を集める
    cursor.execute("SELECT newvalue, time, ticket, field"
                   " from ticket_change"
                   " where ticket=%s"
                   "   and field=%s"
                   "   order by time", (ticket_id, 'status'))
    for row in cursor:
        history.append((row[0], to_datetime(row[1])))
    
    return history
