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

import re, math, ConfigParser, time, platform, os, codecs
from subprocess import Popen, PIPE
from os import path, listdir, makedirs, system
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from urllib import unquote
from datetime import datetime, tzinfo, timedelta
from shutil import copyfile
from distutils.sysconfig import get_python_lib
from jinja2.loaders import FileSystemLoader
from jinja2 import Environment, TemplateNotFound
from werkzeug import script
from markdown import markdown
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

from markdown import Extension
from markdown.extensions import attr_list
from markdown.inlinepatterns import IMAGE_LINK_RE, IMAGE_REFERENCE_RE
from markdown.blockprocessors import BlockProcessor
from markdown.util import etree

from urlparse import urlparse
from os.path import splitext, basename


class Config:
    def __init__(self):
        self.is_parsed = False
        self._parser = ConfigParser.RawConfigParser(allow_no_value=True)
        rc_path = path.expanduser('~/.microrc')
        if path.exists(rc_path):
            self._parser.readfp(codecs.open(rc_path, "r", "utf8"))
            self.is_parsed = True

    def __getattr__(self, option):
        if self.is_parsed:
            config_list = {
                'month': 'locale',
                'days': 'locale',
                'public': 'storage',
                'templates': 'storage',
                'pages': 'storage',
                'posts': 'storage',
                'to': 'sync',
                'key': 'sync',
                'cache': 'system'
            }
            if option in ['templates', 'pages', 'posts', 'public', 'build', 'cache']:
                return path.expanduser(self._parser.get('storage', option))
            elif option == 'blog_path':
                return path.join(self.build, "blog")
            elif option == 'categories_path':
                return path.join(self.blog_path, "categories")
            elif option == 'archives_path':
                return path.join(self.blog_path, "archives")
            elif option == 'exclude_category':
                try:
                    return self._parser.get('system', option).split(',')
                except ConfigParser.NoOptionError:
                    return []
            elif option == 'post_per_page':
                return int(self._parser.get('system', option))
            elif config_list.has_key(option):
                return self._parser.get(config_list[option], option)
            else:
                return self._parser.get('system', option)

    def get_option(self, section, option):
        return self._parser.get(section, option)

config = Config()


class Cache:
    @staticmethod
    def get(key):
        import shelve
        key = str(key)
        filename = config.cache + '/posts.db'
        try:
            posts_cache = shelve.open(filename)
            if posts_cache.has_key(key):
                return posts_cache[key]
            posts_cache.close()
        except Exception as e:
            print e

    @staticmethod
    def set(key, value):
        import shelve
        key = str(key)
        filename = config.cache + '/posts.db'
        try:
            posts_cache = shelve.open(filename, writeback=True)
            posts_cache[key] = value
            posts_cache.close()
        except Exception as e:
            print e


class ImagesProcessor(BlockProcessor):
    FIGURES = [u'^\s*'+IMAGE_LINK_RE+ u'(\{\:?([^\}]*)\})?' + u'\s*$', u'^\s*'+IMAGE_REFERENCE_RE+u'\s*$']
    INLINE_LINK_RE = re.compile(r'\[([^\]]*)\]\(([^)]+)\)(\{\:?([^\}]*)\})?')
    FIGURES_RE = re.compile('|'.join(f for f in FIGURES))

    def test(self, parent, block):
        isImage = bool(self.FIGURES_RE.search(block))
        isOnlyOneLine = (len(block.splitlines()) == 1)

        if (isImage and isOnlyOneLine):
            return True
        else:
            return False

    def run(self, parent, blocks):
        alt = url = attr = None

        raw_block = blocks.pop(0)
        mdImage = self.FIGURES_RE.search(raw_block).group(0)

        rAlt = self.FIGURES_RE.search(raw_block)
        if (rAlt):
            alt = rAlt.group(1)

        rUrl = self.INLINE_LINK_RE.search(mdImage)
        if (rUrl):
            url = rUrl.group(2)

        rAttr = self.INLINE_LINK_RE.search(mdImage)
        if (rAttr):
            attr = self.INLINE_LINK_RE.search(mdImage).group(3)

        public_dir = config.public
        filepath = public_dir + url

        width = height = 0
        img = etree.SubElement(parent, 'img')

        if (attr):
            image_size = self.assignExtra(img, attr)
            width = image_size['width']
            height = image_size['height']

        if (width == 0 and height == 0):
            from PIL import Image
            with Image.open(filepath) as im:
                imageWidth, imageHeight = im.size
                if (imageHeight > 400):
                    height = 400

        if (width > 0 or height > 0):
            disassembled = urlparse(url)
            filename, file_ext = splitext(basename(disassembled.path))

            find = filename + file_ext
            replace = '_/' + filename + '@2x' + file_ext
            hidpiThumb = disassembled.path.replace(find, replace)

            find = filename + file_ext
            replace = '_/' + filename + file_ext
            thumb = disassembled.path.replace(find, replace)

            img.set('srcset', hidpiThumb + ' 2x')
            img.set('src', thumb)
            img.set('data-src-original', url)

            if (height > 0):
                img.set('max-height', str(height) + 'px')

            if (width > 0):
                img.set('max-width', str(width) + 'px')

            cache_key = '[images] ' + filepath
            file_size = os.stat(filepath).st_size
            previous_size = Cache.get(cache_key)

            if (previous_size and previous_size != file_size) or not previous_size:
                print 'Image compressing [' + filename + ']'
                print 'Height [' + str(height) + 'px]'
                print 'Width: [' + str(width) + 'px]'

                self.convert(public_dir, url, height, width)
                Cache.set(cache_key, file_size)

        else:
            img.set('src', url)

        if (alt):
            img.set('alt', alt)

    def convert(self, public_dir, url, height=0, width=0):
        script = '''\
            public_dir=$0
            url=$1
            width=$2
            height=$3

            file=$public_dir$url
            file_name=$(basename "$file")
            ext="${file_name##*.}"
            name="${file_name%.*}"
            dir=$(dirname "${file}")/

            THUMB_PATH=$dir"_"

            [ -d $THUMB_PATH ] || mkdir $THUMB_PATH

            if [ "$#" -eq 3 ] && ([ "$width" -gt 0 ] || [ "$height" -gt 0 ]); then
                if [ "$width" -gt 0 ]; then
                    W=`identify -format '%w' $file`
                    double=$(($width * 2))
                    convert "$file" -resize $double "$THUMB_PATH/${name}@2x.${ext}"
                    convert "$file" -resize $width "$THUMB_PATH/${name}.${ext}"

                else
                    H=`identify -format '%h' $file`
                    double=$(($height * 2))
                    convert "$file" -resize x$double "$THUMB_PATH/${name}@2x.${ext}"
                    convert "$file" -resize x$height "$THUMB_PATH/${name}.${ext}"
                fi
            else
                W=`identify -format '%w' $file`

                if [ "$W" -gt 1600 ]
                then
                    convert "$file" -resize 1600 "$THUMB_PATH/${name}@2x.${ext}"
                    convert "$file" -resize 800 "$THUMB_PATH/${name}.${ext}"
                else
                    cp $file "$THUMB_PATH/${name}@2x.${ext}"
                    convert "$THUMB_PATH/${name}@2x.${ext}" -resize 50% "$THUMB_PATH/${name}.${ext}"
                fi
            fi

            if [ "$ext" == "png" ]; then
                pngquant "$THUMB_PATH/${name}@2x.${ext}" --ext .${ext} --force
                pngquant "$THUMB_PATH/${name}.${ext}" --ext .${ext} --force
            else
                pngquant "$THUMB_PATH/${name}@2x.${ext}" --ext='' --force
                pngquant "$THUMB_PATH/${name}.${ext}" --ext='' --force
            fi
        '''

        import subprocess

        command = ['bash', '-c', script, public_dir, url, str(width), str(height)]
        proc = subprocess.Popen(command)
        proc.communicate()[0]

    # ![By default](/i/ukrainian-keyboard-default.png){: width=400} assign width i.e. <img width="400"/>
    def assignExtra(self, img, attr):
        image_size = {'width': 0, 'height': 0}

        BASE_RE = r'\{\:?([^\}]*)\}'
        INLINE_RE = re.compile(r'^%s' % BASE_RE)
        NAME_RE = re.compile(r'[^A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff'
                             r'\u0370-\u037d\u037f-\u1fff\u200c-\u200d'
                             r'\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff'
                             r'\uf900-\ufdcf\ufdf0-\ufffd'
                             r'\:\-\.0-9\u00b7\u0300-\u036f\u203f-\u2040]+')

        m = INLINE_RE.match(attr)
        if (m):
            attr = m.group(1)

            for k, v in attr_list.get_attrs(attr):
                if k == '.':
                    cls = img.get('class')
                    if cls:
                        img.set('class', '%s %s' % (cls, v))
                    else:
                        img.set('class', v)
                else:
                    key = NAME_RE.sub('_', k)
                    img.set(key, v)

                    if (k == 'width'):
                        image_size['width'] = v

                    if (k == 'height'):
                        image_size['height'] = v

        return image_size


class FigureCaptionExtension(Extension):
    def extendMarkdown(self, md, md_globals):
        md.parser.blockprocessors.add('retina', ImagesProcessor(md.parser), '<ulist')


def makeExtension(configs={}):
    return FigureCaptionExtension(configs=configs)

class Entry:
    def __init__(self, *initial_data, **kwargs):
        for dictionary in initial_data:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])


class Category(Entry):
    pass


class TZ(tzinfo):
    def utcoffset(self, dt):
        return timedelta(minutes=int(config.timezone_offset))


class Date(Entry):
    def get_full(self):
        locale_month = config.month.split(',')
        weekdays = config.days.split(',')
        day = int(self.day)
        month = int(self.month) - 1
        weekday = weekdays[self.get_datetime().weekday()]
        return weekday + ', ' + str(day) + ' ' + locale_month[month] + ' ' + str(self.year)

    def get_half(self):
        locale_month = config.month.split(',')
        weekdays = config.days.split(',')
        day = int(self.day)
        month = int(self.month) - 1
        weekday = weekdays[self.get_datetime().weekday()]
        return weekday + ', ' + str(day) + ' ' + locale_month[month]

    def get_iso(self):
        return self.get_datetime().isoformat()

    def get_datetime(self):
        return datetime(
            int(self.year), int(self.month), int(self.day), int(self.minute), int(self.second), 
            tzinfo=TZ()
        )


class Post(Entry):
    def get_full(self):
        return self.content + self.description

    def get_url(self):
        return 'http://' + config.host + '/blog/' + self.date.year + '/' + self.date.month + '/' + self.date.day + '/' + \
            self.name + '/'

    def has_excluded_cats(self):
        for category in self.categories:
            if category.name in config.exclude_category:
                return True
        return False


class Page(Entry):
    pass

posts_cache = 0

class Press:
    def load_press(self):
        self.load()
        self.load_first_press()
        print "Load complete"

    def generate_partially(self):
        categories = self.gen_categories()
        self.gen_archives()
        self.gen_feed()
        self.gen_sitemap()
        self.gen_subfeeds(categories)
        print "Generation partially done"

    def generate_publishing(self):
        self.gen_articles()
        self.gen_index_range(1)
        self.gen_static()
        self.gen_error()
        print "Generation done"

    def generate(self):
        self.load_press()
        self.generate_partially()
        self.generate_publishing()

    def load_first_press(self):
        year = datetime.now().year
        for post in self.posts:
            if int(post.date.year) < year:
                year = post.date.year
        self.first_press = year

    def gen_index_by_post(self, post):
        page = self.get_post_page_number(post.name) - 1
        self.gen_index_range(page)

    def gen_post(self, post):
        post_path = path.join(config.blog_path, post.date.year, post.date.month, post.date.day, post.name)
        rendered = self.render('article.html', post=post)
        self.write(post_path, rendered)

    def gen_articles(self):
        for post in self.posts:
            self.gen_post(post)

    def count_posts(self):
        if not self.posts_filtered:
            self.load_posts()
        size = len(self.posts_filtered)
        return size

    def count_pages(self, size):
        pages = math.ceil(float(size)/config.post_per_page) if size > config.post_per_page else 1
        pages = int(pages)
        return pages

    def gen_index_range(self, page, end=None):
        size = self.count_posts()
        pages = self.count_pages(size)
        while page <= pages:
            diff = pages * config.post_per_page - size
            if page == pages:
                offset = 0
                offset_to = config.post_per_page if config.post_per_page < size else size
                to = config.build
            elif page == (pages - 1) and size > config.post_per_page:
                offset = config.post_per_page
                offset_to = (config.post_per_page * (pages + 1 - page)) - diff
                to = path.join(config.blog_path, 'page', str(page))
            else:
                offset = (config.post_per_page * (pages - page)) - diff
                offset_to = offset + config.post_per_page
                to = path.join(config.blog_path, 'page', str(page))
            posts = self.posts_filtered[offset:offset_to]
            rendered = self.render('index.html', posts=posts, page=page, total_pages=pages)
            self.write(to, rendered)

            if page == end:
                break

            page += 1

    def gen_categories(self):
        categories = self.sort_by_categories(self.posts)
        for key, value in categories.iteritems():
            category = key.lower()
            category_path = path.join(config.categories_path, category)
            try:
                category_meta = config.get_option('meta', category)
            except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
                category_meta = False
            category_name = value[0].categories[0].name
            rendered = self.render('categories.html', years=self.sort_by_years(value), categories=key,
                                   category_name=category_name, category_meta=category_meta)
            self.write(category_path, rendered)
        return categories

    def gen_archives(self):
        rendered = self.render('categories.html', years=self.sort_by_years(self.posts, True), archive=True)
        self.write(config.archives_path, rendered)

    def gen_feed(self):
        rendered = self.render('atom.xml', posts=self.posts_filtered[0:30], )
        self.write(config.build, rendered, 'atom.xml')

    def gen_sitemap(self):
        rendered = self.render('sitemap.xml', posts=self.posts_filtered)
        self.write(config.build, rendered, 'sitemap.xml')

    def gen_subfeeds(self, categories):
        for key, value in categories.iteritems():
            category_path = path.join(config.categories_path, key.lower())
            rendered = self.render('atom.xml', posts=value, category=key)
            self.write(category_path, rendered, 'atom.xml')

    def gen_static(self):
        for page in self.pages:
            rendered = self.render('page.html', page=page)
            self.write(path.join(config.build, page.name), rendered)

    def gen_error(self):
        try:
            rendered = self.render('error.html')
            self.write(config.build, rendered, 'error.html')
        except TemplateNotFound:
            pass

    def render(self, template, **kwargs):
        template = self.get_base_template(template)
        options = {
            'host': config.host,
            'name': config.name,
            'author': config.author,
            'date': "%s&ndash;%s" % (self.first_press, datetime.now().year),
            'pages': self.pages,
            'datetime_now': datetime.now().replace(tzinfo=TZ(), microsecond=0)
        }
        return template.render(dict(kwargs.items() + options.items()))

    def write(self, to, rendered, additional = 'index.html'):
        if not to.endswith('/'):
            to += '/'
        if not path.exists(path.dirname(to)):
            makedirs(path.dirname(to))
        with open(path.join(to, additional), "w") as file:
            file.write(rendered.encode('utf-8', 'ignore'))

    def get_base_template(self, name):
        template = Environment(loader=FileSystemLoader(config.templates))
        return template.get_template(name)

    def sort_by_years(self, posts, archive=False):
        years = {}
        include = {}
        if archive:
            for post in posts:
                if not (post.has_excluded_cats()):
                    include[post.date.year] = True
        for post in posts:
            if not archive or post.date.year in include:
                if not years.has_key(post.date.year):
                    years[post.date.year] = []
                if archive and (post.has_excluded_cats()):
                    pass
                else:
                    years[post.date.year].append(post)
        return reversed(sorted(years.iteritems()))

    def sort_by_categories(self, posts):
        categories = {}
        for post in posts:
            for category in post.categories:
                if not categories.has_key(category.link):
                    categories[category.link] = []
                categories[category.link].append(post)
        return categories

    def sort_by_feeds(self, posts):
        feeds = {}
        for post in posts:
            if not feeds.has_key(post.categories[0]):
                feeds[post.categories[0]] = []
            feeds[post.categories[0]].append(post)
        return feeds


class Octopress(Press):
    posts = []
    posts_filtered = []
    posts_names = []

    def load(self):
        self.load_posts()
        self.load_pages()

    def is_valid_post(self, name):
        if path.isfile(path.join(config.posts, name)) and not name.startswith('.'):
            return True
        return False

    def load_posts(self, end=None):
        self.posts_filtered = []
        self.posts_names = []
        self.posts = []

        posts_list = reversed(listdir(config.posts))

        i = 0
        for f in posts_list:
            if self.is_valid_post(f):
                try:
                    post = self.parse_post(f)
                    if not post.has_excluded_cats():
                        self.posts_filtered.append(post)
                        self.posts_names.append(post.name)
                    self.posts.append(post)
                    i += 1
                    if i == end:
                        break
                except Exception:
                    pass

    def load_pages(self):
        self.pages = [self.parse_page(f) for f in reversed(listdir(config.pages))
            if path.isfile(path.join(config.pages, f)) and not f.startswith('.')
        ]

    def get_post_page_number(self, name):
        size = self.count_posts()
        pages = self.count_pages(size)

        posts_at_second_page = config.post_per_page - (pages * config.post_per_page - size)
        post_index = self.posts_names.index(name)

        post_per_page = int(config.post_per_page)
        page = pages
        pre_main_page = pages - 1

        i = 0
        j = post_per_page

        while page > 0:
            if page == pre_main_page:
                i += j
                j += posts_at_second_page
            elif page != pages:
                i = j
                j += post_per_page
            if j > post_index >= i:
                return page
            page -= 1

    def parse_post(self, name):
        f = file(path.join(config.posts, name), "r")
        post = f.read().decode('utf-8')

        explode = post.split('---')
        settings = explode.pop(1)
        body = "".join(explode)

        body_list = body.split('<!-- more -->')
        content = body_list.pop(0)
        description = "".join(body_list)

        regenerate = False
        auto_sync = re.search('(?<=autosync:).+', settings)
        if auto_sync:
            sync = auto_sync.group(0).strip()
            if sync == 'true':
                regenerate = True

        time_rows = re.search('(?<=time:).+', settings)

        update_time = False
        if time_rows:
            clear_time = time_rows.group(0).strip()
            if clear_time == '-':
                time_rows = ['00', '00']
                update_time = True
            else:
                time_rows = clear_time.split(':')

        categories = re.search('(?<=categories:).+', settings).group(0).strip()
        categories_list = categories.split(',') if (',' in categories) else categories.split()

        for key, item in enumerate(categories_list):
            category_link = category_name = item.strip()
            if '/' in item:
                explode = item.split("/", 1)
                category_link = explode[1].strip()
                category_name = explode[0].strip()
            categories_list[key] = Category(link=category_link, name=category_name)

        link = re.search('(?<=link:).+', settings)
        if link:
            link = link.group(0).strip()

        date = Date(
            config=config,
            year=name[:4],
            month=name[5:7],
            day=name[8:10],
            minute=time_rows[0] if time_rows else 0,
            second=time_rows[1] if time_rows else 0
        )

        meta_desc = re.search('(?<=meta_desc:).+', settings);
        if meta_desc:
            meta_desc = meta_desc.group(0).strip()[1:-1]

        return Post(
            config=config,
            date=date,
            file=name,
            name=self.parse_name_from_file(name),
            title=re.search('(?<=title:).+', settings).group(0).strip()[1:-1],
            meta_desc=meta_desc,
            content=markdown(content, ['extra', FigureCaptionExtension()]),
            description=markdown(description, ['extra', FigureCaptionExtension()]),
            categories=categories_list,
            link=link,
            sync=regenerate,
            update_time=update_time,
        )

    def parse_name_from_file(self, name):
        r = re.compile("\d{4}-\d{2}-\d{2}-(.*)\.\w+")
        m = r.match(name)
        if m:
            return m.group(1)

    def parse_page(self, name):
        f = file(path.join(config.pages, name), "r")
        page = f.read().decode('utf-8')
        explode = page.split('---')
        settings = explode.pop(1)
        body = "".join(explode)
        return Page(
            name=name[:-9],
            title=re.search('(?<=title:).+', settings).group(0).strip()[1:-1],
            content=markdown(body, ['extra', FigureCaptionExtension()])
        )


class PostsEventHandler(FileSystemEventHandler):
    def on_moved(self, event):
        pass

    def on_created(self, event):
        pass

    def on_deleted(self, event):
        pass

    def on_modified(self, event):
        self.generate(event)

    def generate(self, event):
        filename = path.basename(event.src_path)

        if not filename.startswith('.') and not event.is_directory:
            try:
                engine = Octopress()

                if not path.exists(config.build):
                    system("mkdir -p " + config.build)
                    engine.generate()

                post = engine.parse_post(filename)
                engine.load_pages()
                engine.load_posts()
                engine.load_first_press()

                if post.update_time and post.sync:
                    self.update_time(post.file)

                engine.gen_index_by_post(post)
                engine.gen_post(post)

                if post.sync:
                    engine.generate_partially()
                    action_sync()

                print 'Post dispatched successfully.'

            except Exception as e:
                print 'Invalid post format or permissions not found'

    @staticmethod
    def update_time(filename):
        src = path.join(config.posts, filename)
        with open(src) as f:
            content = f.read()
        current_time = 'time: ' + datetime.now().strftime('%H:%M')
        f = re.compile('(time: -)')
        new = f.sub(current_time, content)
        with open(src, "w") as f:
            f.write(new)


class Server(BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            if self.path[-1:] == '/':
                self.path += 'index.html'
            f = open(config.build + unquote(self.path))
            self.send_response(200)
            self.end_headers()
            self.wfile.write(f.read())
            f.close()
            return
        except IOError:
            self.send_error(404, 'File not found')


def action_sync():
    storage = False
    try:
        storage = config.get_option('sync', 'type')
    except ConfigParser.NoOptionError:
        pass

    if storage == 's3':
        bucket = config.get_option('sync', 'bucket')
        build = config.build + "/"

        access_key_id = config.get_option('sync', 'access_key_id')
        secret_access_key = config.get_option('sync', 'secret_access_key')

        s3cmd = "/usr/local/bin/s3cmd sync -r --access_key=%s --secret_key=%s --acl-public --no-mime-magic --guess-mime-type" % (access_key_id, secret_access_key)

        system(s3cmd + " --rexclude='.css$|.js$|.jpg|.png|.gif|$' %s s3://%s" % (build, bucket))
        system(s3cmd + " --rinclude='.css$|.js$|.jpg|.png|.gif|$' --add-header='Cache-Control:max-age=604800' --cf-invalidate %s s3://%s" % (build, bucket))
    elif storage == 'git':
        build = config.build + "/"
        command = '/usr/bin/git -C ' + build
        system(command + " add . ")
        system(command + " commit --amend -m %s" % ('"Micropress autogenerator update"'))

        # push
        try:
            print 'git push started'
            cmd = "find /tmp/com.apple.launchd.*/Listeners -type s | head -1"
            ssh_auth_agent = os.popen(cmd).read().strip()
            identity_key = path.expanduser(config.key)
            args = ['/usr/bin/git', '-C', build, 'push', '--force-with-lease']
            env = dict(os.environ)
            env['SSH_AUTH_SOCK'] = ssh_auth_agent
            env['GIT_SSH_COMMAND'] = "ssh -i " + identity_key
            p = Popen(args, stdout=PIPE, stderr=PIPE, env=env)
            p.communicate()
        except Exception:
            print 'Error running git push'
    else:
        try:
            print 'rsync started'
            cmd = "find /tmp/com.apple.launchd.*/Listeners -type s | head -1"
            ssh_auth_agent = os.popen(cmd).read().strip()
            identity_key = path.expanduser(config.key)
            source = path.join(config.build, '')
            ssh_args = ['-e', '/usr/bin/ssh -i ' + identity_key]
            args = ['/usr/bin/rsync', '-a', '-v', '-r'] + ssh_args + [source, config.to]
            env = dict(os.environ)
            env['SSH_AUTH_SOCK'] = ssh_auth_agent
            p = Popen(args, stdout=PIPE, stderr=PIPE, env=env)
            p.communicate()
        except Exception:
            print 'Error running rsync'

    print('Sync done')


def action_s3logs():
    bucket = config.get_option('sync', 'bucket')
    access_key_id = config.get_option('sync', 'access_key_id')
    secret_access_key = config.get_option('sync', 'secret_access_key')

    system("s3cmd sync -r --access_key=%s --secret_key=%s --acl-public s3://%s/logs %s"
        % (access_key_id, secret_access_key, bucket, config.build + "/"))


def action_preview():
    server_address = ('127.0.0.1', 8080)
    httpd = HTTPServer(server_address, Server)
    print('Http server is running on http://127.0.0.1:8080')
    httpd.serve_forever()


def action_generate():
    engine = Octopress()
    if not path.exists(config.build):
        system("mkdir -p " + config.build)
    engine.generate()
    system("cp -r " + config.public + "/* " + config.build)


def action_gp():
    action_generate()
    action_preview()


def action_gs():
    action_generate()
    action_sync()


def action_init():
    if platform.system() in ('Linux', 'Darwin'):
        src = path.join(get_python_lib(), 'micropress', 'init')
        dst = path.expanduser('~/Documents/Micropress/')

        if not path.exists(dst):
            makedirs(dst, 0755)

            # copy default public sources templates
            system('cp -r ' + path.join(src, '*') + ' ' + dst)
            system('rm -r ' + path.join(dst, 'launch_agents') + ' ' + path.join(dst, 'build'))
            print 'Default src saved in ' + dst

        # copy default config if not found
        config_src = path.join(src, '.microrc')
        config_dst = path.expanduser('~/.microrc')

        if not path.exists(config_dst):
            copyfile(config_src, config_dst)
            print('Config successfully saved in ~/.microrc')

        global config
        config = Config()
        action_generate()

    if platform.system() == 'Darwin':
        launch_agents_src = path.join(src, 'launch_agents')
        launch_agents_dst = '~/Library/LaunchAgents/'

        watcher_name = 'co.fluder.micropress.watcher.plist'
        preview_name = 'co.fluder.micropress.preview.plist'

        watcher_src = path.join(launch_agents_src, watcher_name)
        preview_src = path.join(launch_agents_src, preview_name)

        watcher_dst = path.expanduser(launch_agents_dst + watcher_name)
        preview_dst = path.expanduser(launch_agents_dst + preview_name)

        copyfile(watcher_src, watcher_dst)
        system('launchctl unload -w ' + watcher_dst)
        system('launchctl load -w ' + watcher_dst)
        print "Watcher LaunchAgents rule loaded successful."

        copyfile(preview_src, preview_dst)
        system('launchctl unload -w ' + preview_dst)
        system('launchctl load -w ' + preview_dst)
        print "Preview LaunchAgents rule loaded successful."


def action_watch():
    posts_path = config.posts
    event_handler = PostsEventHandler()
    observer = Observer()
    observer.schedule(event_handler, posts_path, recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()


def action_add(name=('n', '')):
    template_dst = path.join(config.posts, '') + time.strftime("%Y-%m-%d") + '-' + name + '.md'
    template_src = path.join(get_python_lib(), 'micropress', 'init', 'templates', 'base.markdown')
    if os.path.isfile(template_dst):
        print 'File exist already.'
    else:
        copyfile(template_src, template_dst)
        system("vim " + template_dst)


if __name__ == '__main__':
    script.run()
