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

from trac.core import *
from trac.mimeview.api import IContentConverter, Context
from trac.ticket.api import TicketSystem
import pyExcelerator
from trac.resource import Resource
from custumPyExcelerator import *
import re
from trac.ticket.model import Ticket
from trac.util.datefmt import to_timestamp
from datetime import datetime

class ExcelReportExport(Component):
    u"""カスタムレポートの抽出結果をExcel形式で出力するプラグイン。
    なお、カスタムレポートの抽出結果はIDのリストのみを使用し、
    項目は無条件で出力します（不要な項目はExcelのファイル側で削除してください）。
    なお、コメントが記入されている場合は、右方向へ追記していきます。
    （256列を超えた場合の挙動は確認していません）
    
    Excelファイルの作成に、pyExceleratorを使用しているので、あらかじめインストールしておいてください。
    http://sourceforge.net/projects/pyexcelerator
    今回は、Ver0.6.3aで動作確認しています（2005年秋以降更新されていない？）
    zipファイルをダウンロードして展開し、普通に python setup.py install でインストールできます。
    """
    implements(IContentConverter)

    # ステータス毎の背景色
    statuscolor = {}

    # IContentConverter methods
    def get_supported_conversions(self):
        # IContentConverterを使用すると、いい感じでダウンロードリンクを追加できる。
        # 第１引数はformatで第２引数が画面のテキスト、第３引数が拡張子、
        # 第４の引数は対象となる機能、第５引数がmime-type。最後の引数は・・・？
        yield ('excel', 'Excel', 'xls',
               'trac.ticket.Query', 'application/vnd.ms-excel ', 8)

    def convert_content(self, req, mimetype, query, key):
        if key == 'excel':
            return self.export_excel(req, query)

    # 背景色の設定を読み込む
    def load_bgcolor(self, ticketfields):
        # 定義されているステータス一覧
        statuslist = []
        for field in ticketfields:
            if field['name'] == 'status':
                statuslist = field['options']

        for status in statuslist:
            color = self.env.config.get('excelreportexport', 'bgcolor.%s' % status)
            style = self.get_wrap_cell()
            if color:
                pattern = pyExcelerator.Formatting.Pattern()
                pattern.pattern = pyExcelerator.Formatting.Pattern.SOLID_PATTERN
                # 背景色を指定する場合だが、厳密には、「パターン＋前景色」となる
                pattern.pattern_fore_colour = int(color, 16)
                style.pattern = pattern
            self.statuscolor[status] = style

        self.statuscolor['none'] = self.get_wrap_cell()
    
    # Excel Export
    def export_excel(self, req, query):
        # ワークブック作成
        workbook = CustomWorkbook()
        # シート作成
        worksheet = workbook.add_sheet("Ticket")

        # １行目にヘッダー情報（フィールド一覧）を出力する。
        ticketfields = TicketSystem(self.env).get_ticket_fields()
        self.createheader(ticketfields, worksheet)

        # 定義されているステータス一覧
        self.load_bgcolor(ticketfields)

        # チケットデータを取得する＆出力する
        context = Context.from_request(req)
        results = query.execute(req, self.env.get_db_cnx())
        row = 1
        textcellstyle = self.get_text_cell()
        wrapcellstyle = self.get_wrap_cell()
        numericcellstyle = self.get_numeric_cell()
        datecellstyle = self.get_date_cell()
        worksheet.col(0).width = 6 * 256
        worksheet.col(1).width = 20 * 256
        worksheet.col(2).width = 20 * 256
        for result in results:
            ticketid = result['id']
            ticket = Resource('ticket', ticketid)
            if 'TICKET_VIEW' in req.perm(ticket):
                ticket = Ticket(self.env, ticketid)
                changelog = ticket.get_changelog()
                worksheet.write(row, 0, label = ticketid, style = numericcellstyle)
                # 作成日・更新日
                worksheet.write(row, 1, label = datetime.fromtimestamp(to_timestamp(ticket.time_created)), style = datecellstyle)
                worksheet.write(row, 2, label = datetime.fromtimestamp(to_timestamp(ticket.time_changed)), style = datecellstyle)
                col = 3
                for field in ticketfields:
                    key = field['name']
                    value = ticket.values.get(key) or ''
                    if key in ['description', 'summary']:
                        worksheet.write(row, col, label = value, style = wrapcellstyle)
                        worksheet.col(col).width = 50 * 256 # 1/256 が単位
                    else:
                        worksheet.write(row, col, label = value, style = textcellstyle)
                    col += 1
                # 変更履歴のコメントを登録する
                changedate = None
                commenttext = None
                status = None
                attachmentcomment = False
                for log in changelog:
                    if changedate and changedate != log[0]:
                        # ログが切り替わった
                        if commenttext and not attachmentcomment:
                            self.write_comment(status, commenttext, worksheet, row, col)
                            col += 1
                        commenttext = None
                        status = None
                        attachmentcomment = False
                    if log[2] == 'comment':
                        commenttext = log[4]
                    elif log[2] == 'attachment':
                        attachmentcomment = True
                    elif log[2] == 'status':
                        status = log[4]
                    changedate = log[0]
                    
                # 最後の１件
                if len(changelog) != 0:
                    if commenttext and not attachmentcomment:
                        self.write_comment(status, commenttext, worksheet, row, col)
 
                row += 1

        # クライアントにデータを戻す場合、単にworkbook.get_biff_data()のデータを
        # 流し込むだけではだめなので、カスタマイズしたworkbookを使用している。
        return workbook.getdata(), 'application/vnd.ms-excel'

    # コメントを書き込む
    def write_comment(self, status, commenttext, worksheet, row, col):
        bgcolor = None
        style = self.get_wrap_cell()
        s = status or 'none'
        style = self.statuscolor[s]
        worksheet.write(row, col, label = commenttext, style = style)
        worksheet.col(col).width = 50 * 256 # 1/256 が単位


    # 共通セル書式
    def get_default_cell(self):
        style = pyExcelerator.XFStyle()
        font = pyExcelerator.Formatting.Font()
        font.name = u'ＭＳ ゴシック'
        font.height = 10 * 20 # 1/20単位なので*20することでpt数になる
        style.font = font
        borders = pyExcelerator.Formatting.Borders()
        borders.bottom = pyExcelerator.Formatting.Borders.THIN
        borders.top = pyExcelerator.Formatting.Borders.THIN
        borders.left = pyExcelerator.Formatting.Borders.THIN
        borders.right = pyExcelerator.Formatting.Borders.THIN
        style.borders = borders
        return style

    # 文字データ出力用のセル書式を出力する
    def get_text_cell(self):
        style = self.get_default_cell()
        style.num_format_str = "general"
        return style

    # 文字データ出力（文字列折り返し）
    def get_wrap_cell(self):
        style = self.get_default_cell()
        style.num_format_str = "general"
        alignment = pyExcelerator.Formatting.Alignment()
        alignment.wrap = pyExcelerator.Formatting.Alignment.WRAP_AT_RIGHT
        style.alignment = alignment
        return style

    # 数値データ出力用（といってもバージョン番号くらいか？）のセル書式
    def get_numeric_cell(self):
        style = self.get_default_cell()
        style.num_format_str = "0"
        return style

    # 日付データ出力用のセル書式（作成日・更新日用）
    def get_date_cell(self):
        style = self.get_default_cell()
        style.num_format_str = "YYYY/MM/DD hh:mm:ss"
        return style

    # ヘッダー行を作成する
    def createheader(self, ticketfields, worksheet):
        style = self.get_default_cell()
        style.font.bold = True
        style.num_format_str = "general" # 文字列フォーマット
        # セルの水平・垂直揃えを中央にする
        alignment = pyExcelerator.Formatting.Alignment()
        alignment.horz = pyExcelerator.Formatting.Alignment.HORZ_CENTER
        alignment.vert = pyExcelerator.Formatting.Alignment.VERT_CENTER
        style.alignment = alignment

        worksheet.write(0, 0, label = 'ID', style = style)
        worksheet.write(0, 1, label = u'作成日', style = style)
        worksheet.write(0, 2, label = u'更新日', style = style)
        col = 3
        for field in ticketfields:
            # 書込
            worksheet.write(0, col, label = field['label'], style = style)
            col += 1

