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

import sys
import enchant
import argparse
import re
import time
import subprocess
import os 
from os.path import expanduser, join

RUSSIAN_LETTERS = 'йцукенгшщзхъфывапролджэячсмитьёбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮЁ'
DICT_PATH = '/etc/branch-spell-check/dict.txt'
USER_DICT = join(expanduser('~'), '.branch-spell-check.dict')
DIFF = []
RED = '\033[91m'
END = '\033[0m'

dictionary = enchant.DictWithPWL("ru", DICT_PATH)
user_dict = []

def log(msg):
    LOG_FILE.write('%s: %s\n' % (time.asctime(),  msg))

def create_parser():
    parser = argparse.ArgumentParser(description='Скрипт проверки грамматики', formatter_class=argparse.RawDescriptionHelpFormatter, 
            epilog='Проверяет грамматику русских слов по диффу бранча и транк.\nПример запуска:\n\tbranch-spell-check -b DIRECT-70397-branch')
    parser.add_argument('-b', '--branch', help='проверяемый бранч')
    return parser

def get_branch_trunk_diff(branch):
    global DIFF 
    try:
        command = "svn-diff-branch -s "
        if branch: command += branch
        out = subprocess.check_output(command, shell=True)
        DIFF = out.splitlines()
        return DIFF
    except subprocess.CalledProcessError as error:
        log("svn-diff-branch завершился с ненулевым кодом возврата: %s" % error.returncode) 
        exit(1)

def get_patches(lines):
    patches = []
    count = len(lines)
    i = 1
    while i < count:
        if not lines[i].startswith("Index: "):
            raise ValueError("Illegal diff file format")
        fileName = lines[i].replace("Index: ", "")[:-1]
        i += 4 #skip preamble
        added_lines = []
        while  i < count and not lines[i].startswith("Index: "):
            if lines[i].startswith("+"):
                added_lines.append({
                    'added_line': lines[i][1:],
                    'diff_line': i
                    })

            i += 1
        patches.append({
            'fileName': fileName,
            'added_lines': added_lines
            })
        if i == count: break
    return patches

def check_patch(patch):
    added_lines = patch['added_lines']
    mistakes = 0
    for line in added_lines:
        mistakes += check_line(line['added_line'], line['diff_line'])
    return mistakes

def check_line(line, diff_line):
    words = get_russian_words_from_line(line)
    mistakes = 0
    if len(words) > 0:
        for word in words:
            if not dictionary.check(word) and not word in user_dict:
                mistakes += 1
                shouldSkipLine = correct_or_skip_word(word, line, diff_line)
                if shouldSkipLine:
                    break
    return mistakes

def correct_or_skip_word(word, line, diff_line):
    colored_word = RED + word + END
    print(chr(27) + "[2J")
    print("=" * 70)
    print("\n".join(DIFF[diff_line - 5: diff_line + 5]).replace(line, line.replace(word, colored_word)))
    print("=" * 70)
    c = raw_input('Чтобы запомнить слово нажмите s, что бы пропустить нажмите Enter, что бы пропустить строку нажмите l:')
    if c == 's' or c == 'S':
        save_word(word)
    if c == 'l' or c == 'L':
        return True
    return False

def save_word(word):
    global user_dict
    with open(USER_DICT, 'a') as user_dict_file:
        user_dict.append(word)
        user_dict_file.write('%s\n' % word)

def read_user_dict():
    with open(USER_DICT, 'a+') as user_dict_file:
        return [line.strip() for line in user_dict_file.readlines()]

def get_russian_words_from_line(line):
    if re.match('^[^' + RUSSIAN_LETTERS + ']*((//)|(#)).*[' + RUSSIAN_LETTERS + ']+.*$', line):
        return []
    else:
        return re.findall('[' + RUSSIAN_LETTERS + '][' + RUSSIAN_LETTERS + '-]+', line.replace("«", "").replace("»", ""))

if __name__ == "__main__": 
    LOG_FILE = sys.stdout
    user_dict = read_user_dict()
    params = create_parser().parse_args(sys.argv[1:])
    patches = get_patches(get_branch_trunk_diff(params.branch))
    mistakes = 0
    for patch in patches: mistakes += check_patch(patch)
    log(u'найдено проблемных мест %d' % mistakes)
