import json
import os
import re
import subprocess

from .base import Base


class Source(Base):

    def __init__(self, vim):
        Base.__init__(self, vim)

        self.name = 'go'
        self.mark = '[go]'
        self.filetypes = ['go']
        self.input_pattern = r'[^. \t0-9]\.\w*'

    def get_complete_position(self, context):
        m = re.search(r'\w*$', context['input'])
        return m.start() if m else -1

    def gather_candidates(self, context):
        line = self.vim.current.window.cursor[0]
        column = context['complete_position']

        buf = self.vim.current.buffer
        buf_path = buf.name
        offset = self.ByteOffset(buf, line, column)
        source = '\n'.join(buf).encode()

        process = subprocess.Popen([self.GoCodeBinary(),
                                    '-f=json',
                                    'autocomplete',
                                    buf_path,
                                    str(offset)],
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   start_new_session=True)
        process.stdin.write(source)
        stdout_data, stderr_data = process.communicate()
        result = json.loads(stdout_data.decode('utf-8'))

        out = []
        try:
            for complete in result[1]:
                word = complete['name']
                class_type = complete['class']

                if class_type == 'package':
                    word += '.'
                elif class_type == 'func':
                    word += '('
                elif complete['type'] == '[]string':
                    word += '['

                out.append(dict(word=word,
                                abbr=complete['name'],
                                kind='{:5}'.format(class_type) +
                                complete['type'].replace('func', ''),
                                info=complete['type'],
                                icase=1,
                                dup=1
                                ))

            return out
        except Exception:
            return []

    def ByteOffset(self, buf, line, column):
        offset = -1
        cursor_line = 1
        if line == 1:
            return 1
        else:
            for i, byte in enumerate(buf):
                if cursor_line == line:
                    break
                offset += len(str(byte).expandtabs(tabsize=4))
                cursor_line += 1
            return offset + (column - 1)

    def GoCodeBinary(self):
        try:
            binary_path = self.vim.vars['deoplete#sources#go#gocode_binary']
            if binary_path:
                if os.path.isfile(binary_path):
                    return binary_path
                else:
                    return None
        except Exception:
            return self.FindBinaryPath('gocode')

    def FindBinaryPath(self, cmd):
        def is_exec(fpath):
            return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

        fpath, fname = os.path.split(cmd)
        if fpath:
            if is_exec(cmd):
                return cmd
        else:
            for path in os.environ["PATH"].split(os.pathsep):
                path = path.strip('"')
                binary = os.path.join(path, cmd)
                if is_exec(binary):
                    return binary
        return None

@@ -666,24 +666,31 @@
 uf, line
-, 
+) + (
 column
+ - 1
 )%0A      
@@ -2270,16 +2270,8 @@
 line
-, column
 ):%0A 
@@ -2286,18 +2286,17 @@
 ffset = 
--1
+0
 %0A       
@@ -2355,34 +2355,16 @@
 eturn 1%0A
-        else:%0A    
         
@@ -2390,28 +2390,24 @@
 erate(buf):%0A
-    
             
@@ -2430,24 +2430,48 @@
 = line:%0A    
+            offset += 1%0A
             
@@ -2480,16 +2480,34 @@
   break%0A
+            else:%0A
         
@@ -2524,16 +2524,17 @@
 fset += 
+(
 len(str(
@@ -2542,30 +2542,13 @@
 yte)
-.expandtabs(tabsize=4)
+) + 1
 )%0A  
@@ -2578,36 +2578,32 @@
 ne += 1%0A        
-    
 return offset + 
@@ -2599,31 +2599,16 @@
 n offset
- + (column - 1)
 %0A%0A    de

Fix line2byte python emulate