#!/usr/bin/env python3

import os
import sys
import json
import appdirs
import argparse
import requests
import mimetypes

class argument_parser(argparse.ArgumentParser):
    def __init__(self, is_piped):
        super().__init__(description='Paste a text file to a Sticky Notes pastebin service.',
                         formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        self.add_argument('--private', default=False, action='store_true', help='hides the paste from the public list')
        self.add_argument('--language', type=str, default='autodetect', help='specifies the GeSHi language file to use for the highlighting')
        self.add_argument('--service', type=str, default=argparse.SUPPRESS, help='URL of the Sticky Notes service to use')
        self.add_argument('--expire', type=int, default=argparse.SUPPRESS, help='expiration time in seconds (or 0 to make it permanent)')
        self.add_argument('--user', type=str, default=argparse.SUPPRESS, help='an alphanumeric username of the paste author')
        self.add_argument('--password', type=str, default=argparse.SUPPRESS, help='a password string to protect the paste')
        self.add_argument('filename', type=str, nargs="*", help='the text file to submit to the pastebin service')

    def parse_args(self):
        return vars(super().parse_args())

class configuration(dict):
    _default = {
        'user': 'Anonymous',
        'service': 'http://paste.chakra-project.org/',
    }

    def __init__(self):
        data_dir = appdirs.user_data_dir('chakra-paste', 'The Chakra Project')

        if not os.path.isdir(data_dir):
            os.makedirs(data_dir)

        self.config_file = os.path.join(data_dir, 'config.json')
        self.update(configuration._default)

        try:
            with open(self.config_file, 'r', encoding='utf-8') as config:
                self.update(json.load(config))
        except:
            self.write_config()

    def write_config(self):
        with open(self.config_file, 'w+', encoding='utf-8') as config:
            config.write(json.dumps(
                self,
                sort_keys=True,
                indent=4,
                separators=(',', ': ')))

class paste(object):
    _private_map = {
        True: 'yes',
        False: 'no'
    }

    def __init__(self, configuration):
        self.config_dict = configuration

    def create_from_file(self, filename):
        language = self.config_dict['language']
        if 'autodetect' == language:
            language = mime_to_language.autodetect(filename)

        with open(filename, 'r', encoding='utf-8') as body:
            return self.create_from_string(body.read(), language)

    def create_from_string(self, string, language='text'):
        post_body = {
            'api_submit': True,
            'mode': 'json',
            'paste_data': string,
            'paste_lang': language,
            'paste_private': paste._private_map[self.config_dict['private']]
        }

        if 'expire' in self.config_dict:
            post_body['paste_expire'] = self.config_dict['expire']

        if 'project' in self.config_dict:
            post_body['paste_project'] = self.config_dict['project']

        if 'user' in self.config_dict:
            post_body['paste_user'] = self.config_dict['user']

        if 'password' in self.config_dict:
            post_body['paste_password'] = self.config_dict['password']

        r = requests.post(self.config_dict['service'], data=post_body)
        return self.get_url(r.json())

    def get_url(self, response):
        hostname = self.config_dict['service'].rstrip('/')
        if not self.config_dict['private']:
            return '{host}/{id}'.format(
                host=hostname,
                id=response['result']['id'])
        else:
            return '{host}/{id}/{hash}'.format(
                host=hostname,
                id=response['result']['id'],
                hash=response['result']['hash'])

class mime_to_language(object):
    _mime_table = {
        'text/plain': 'text',
        'text/css': 'css',
        'text/x-actionscript': 'actionscript3',
        'application/x-actionscript': 'actionscript3',
        'application/x-applescript': 'applescript',
        'text/html': 'html5',
        'text/java': 'java',
        'text/x-java': 'java',
        'text/x-java-source': 'java',
        'application/ms-java': 'java',
        'text/ecmascript': 'javascript',
        'application/json': 'javascript',
        'application/javascript': 'javascript',
        'text/x-makefile': 'makefile',
        'text/x-pascal': 'pascal',
        'application/x-perl': 'perl',
        'text/x-php': 'php',
        'text/x-python': 'python',
        'text/x-shellscript': 'bash'
    }

    _extension_table = {
        '.as': 'actionscript3',
        '.asp': 'asp',
        '.awk': 'awk',
        '.cs': 'csharp',
        '.css': 'css',
        '.html': 'html5',
        '.ini': 'ini',
        '.java': 'java',
        '.js': 'javascript',
        '.json': 'javascript',
        '.mk': 'makefile',
        '.pas': 'pascal',
        '.php': 'php',
        '.pl': 'perl',
        '.py': 'python',
        '.rb': 'ruby',
        '.sh': 'bash',
        '.sql': 'sql',
        '.vim': 'vim'
    }

    _filename_table = {
        '.htaccess': 'apache',
        'httpd.conf': 'apache',
        'apache.conf': 'apache',
        'apache2.conf': 'apache',
        'sources.list': 'apt_sources',
        'CMakeLists.txt': 'cmake',
        'xorg.conf': 'xorg_conf'
    }

    @staticmethod
    def autodetect(filename):
        return mime_to_language.guess_from_file_name(filename) \
            or mime_to_language.guess_from_mime_type(filename) \
            or 'text'

    @staticmethod
    def guess_from_file_name(filename):
        filename = os.path.basename(filename)
        if filename in mime_to_language._filename_table:
            return mime_to_language._filename_table[filename]
        extension = os.path.splitext(filename)[1]
        if extension in mime_to_language._extension_table:
            return mime_to_language._extension_table[extension]
        return None

    @staticmethod
    def guess_from_mime_type(filename):
        mime_type = mimetypes.guess_type(filename, strict=False)
        if mime_type[0] in mime_to_language._mime_table:
            return mime_to_language._mime_table[mime_type[0]]
        return None

is_piped = not sys.stdin.isatty()

parser = argument_parser(is_piped)
args_dict = parser.parse_args()

config_dict = configuration()
config_dict.update(args_dict)

try:
    p = paste(config_dict)

    if is_piped:
        print(p.create_from_string(sys.stdin.read()))

    for filename in config_dict['filename']:
        print(p.create_from_file(filename))
except Exception as ex:
    print(ex)

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
