#!/usr/bin/env python
#-*- coding: UTF-8 -*-

'snoa134,YrG14Ikj-bxO8rVWgEAy'

__author__ = 'helljump'


from PyQt4 import QtGui
from PyQt4 import QtCore
import logging
# noinspection PyUnresolvedReferences
import startup
import os
import sys
from os.path import split
import transaction
from utils import MyProgressDialog
import ftputil
import zipfile
from datetime import datetime
from jinja2 import Environment
from StringIO import StringIO
from shopgen import MyExtension
from kadaver_f import _write
from formlayout import fedit, OpenFile, Password
import json
import re


log = logging.getLogger(__name__)


class Worker(QtCore.QThread):

    success = QtCore.pyqtSignal(unicode)
    fail = QtCore.pyqtSignal(unicode)

    def __init__(self, task, parent):
        QtCore.QThread.__init__(self, parent)
        self.task = task
        self.active = True

    def run(self):
        try:
            for info in self.task():
                if not self.active:
                    break
                if isinstance(info, unicode):
                    self.success.emit(info)
                elif isinstance(info, int):
                    self.success.emit(u'Выгрузка документов %i' % info)
        except:
            log.exception('worker error')
            transaction.abort()
            exctype, value = sys.exc_info()[:2]
            self.fail.emit(unicode(value))


class FtpFS(object):

    def __init__(self, host):
        self.host = host

    def save(self, fname, data):
        source = StringIO(data)
        with self.host.open(fname, "wb") as target:
            self.host.copyfileobj(source, target)

    def isdir(self, name):
        return self.host.path.isdir(name)

    def isfile(self, name):
        return self.host.path.isfile(name)

    def makedirs(self, name):
        return self.host.makedirs(name)


class Kadaver(object):

    W, H = 1140, 250

    def __init__(self, prj):
        if hasattr(sys, "frozen"):
            egg = os.path.dirname(sys.executable)
        else:
            egg = 'build\\exe.win32-2.7'
        self.zipname = unicode(egg + '\\tools\\cadaver.zip', encoding=sys.getfilesystemencoding())
        self.env = Environment(extensions=["jinja2.ext.loopcontrols", MyExtension])
        prefs = prj.root()['prefs']
        self.prefs = prefs['deploy/cadaver']
        self.prj = prj
        if self.prefs['image']:
            self.image = QtGui.QImage(self.prefs['image'])
            if self.image.width() > self.W or self.image.height() > self.H:
                self.image = self.image.scaled(self.W, self.H, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
        else:
            self.image = None

    def _upload_zip(self, host):
        zz = zipfile.ZipFile(self.zipname)
        for name in zz.namelist():
            d, f = split(name)
            if f == '.777' and d:
                yield u'Выставляем права %s' % d
                log.debug('chmod dir %s' % d)                
                try:
                    host.chmod(d, 0o777)
                except ftputil.error.PermanentError:
                    log.exception('don\'t chmoded % s', d)
                for el in host.listdir(d):
                    egg = host.path.join(d, el)
                    try:
                        host.chmod(egg, 0o777)
                        log.debug('chmod file %s' % el)
                    except ftputil.error.PermanentError:
                        log.exception('don\'t chmoded % s', egg)
                continue
            if d:
                if not host.path.isdir(d):
                    yield u'Создаем каталог %s' % d
                    log.debug('create dir %s' % d)
                    host.makedirs(d)
            if f:
                if f.endswith('.jinja'):
                    log.debug('translate template %s' % name)
                    tmpl = self.env.from_string(unicode(zz.read(name), 'utf-8'))
                    source = StringIO(tmpl.render(self.prefs).encode('utf-8'))
                    outname = name[:-6]
                else:
                    source = zz.open(name, 'r')
                    outname = name
                if host.path.exists(name):
                    rtime = datetime.fromtimestamp(host.path.getmtime(outname))
                    ltime = datetime(*zz.getinfo(name).date_time)
                    if rtime > ltime:
                        log.debug('skip file %s' % name)
                        continue
                yield u'Заливаем %s' % outname
                log.debug('upload file %s' % outname)
                with host.open(outname, "wb") as target:
                    host.copyfileobj(source, target)
        zz.close()

    def _upload_data(self, host):
        for j in _write(self.prj, '', slugform=self.prefs['slug'], overwrite=self.prefs['overwrite'], fs=FtpFS(host)):
            log.debug("deploy %i", j)
            yield j
        if self.image is not None:
            yield u'Заливаем шапку'
            buff = QtCore.QBuffer()
            self.image.save(buff, 'JPG')
            fout = host.open('template/header.jpg', "wb")
            host.copyfileobj(StringIO(buff.data()), fout)

    def __call__(self):
        yield u'Подключение'
        egg = json.dumps(self.prefs, indent=2)
        egg = re.sub('"password": ".+?",', '"password": "***",', egg)
        log.debug("ftp params %s", egg)
        with ftputil.FTPHost(self.prefs['addr'], self.prefs['user'], self.prefs['password']) as host:
            egg = self.prefs['path'].encode('ascii')
            host.chdir(egg)
            yield u'Заливаем Кадавр'
            for j in self._upload_zip(host):
                yield j
            yield u'Заливаем данные'
            for j in self._upload_data(host):
                yield j

    @staticmethod
    def setup(prj, parent):
        prefs = prj.root()['prefs']
        p = prefs.get('deploy/cadaver', {})
        rc = fedit([
            (u'FTP', p.get('addr', u'')),
            (u'Пользователь', p.get('user', u'')),
            (u'Пароль', Password(p.get('password', u''))),
            (u'Путь установки', p.get('path', u'/public_html')),
            (None, None),
            (u'Заголовок сайта', p.get('title', u'Новый сайт')),
            (u'Изображение в шапке', OpenFile(p.get('image', u''), filter=u'Изображения (*.jpg;*.gif;*.png)')),
            (None, u'Рекомендуемый размер 1140x250'),
            (u'Ключевые слова', p.get('keywords', u'')),
            (u'Описание', p.get('description', u'')),
            (u'Автор', p.get('author', u'Медведь')),
            (u'Почтовый адрес', p.get('email', u'ad@min.ru')),
            (u'Sape ID', p.get('sape', u'')),
            (u'Корзина заказа', p.get('cart', False)),
            (u'Слаг', p.get('slug', u'%Y-%m-%d/%%(slug)s')),
            (u'Перезапись', p.get('overwrite', True)),
        ], u'Установка сайта', parent=parent, icon=QtGui.QIcon(':/aaaa.png'))
        if not rc:
            return
        prefs['deploy/cadaver'] = dict(zip(['addr', 'user', 'password', 'path', 'title', 'image', 'keywords', 'description',
                                            'author', 'email', 'sape', 'cart', 'slug', 'overwrite'], rc))
        transaction.commit()
        return Kadaver(prj)


def process(prj, parent=None):

    k = Kadaver.setup(prj, parent)
    if k is None:
        return

    pdlg = MyProgressDialog(u'Установка сайта', u'Подключение', u'Отмена', 0, 0, parent=parent)
    th = Worker(k, parent)

    def fail(msg):
        log.debug('errormsg!')
        pdlg.close()
        if th.isRunning():
            th.success.disconnect()
            th.fail.disconnect()
            th.finished.disconnect()
        QtGui.QMessageBox.critical(parent, u'Ошибка установки', msg)

    def success(msg):
        pdlg.set_text(msg)

    def closed():
        log.debug('pclosed')
        th.active = False
        th.success.disconnect()
        th.fail.disconnect()
        th.finished.disconnect()

    th.success.connect(success)
    th.fail.connect(fail)
    th.finished.connect(pdlg.close)
    pdlg.closed.connect(closed)
    th.start()
    pdlg.exec_()


if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)

    root = startup.CONN.root()
    prj = root["projects"][0]
    prj.open()
    process(prj, None)
    prj.close()

