# vim:fileencoding=utf-8

import os
import vim
import socket
import struct
import contextlib

fcitxsocketfile = vim.eval('s:fcitxsocketfile')

class FcitxComm(object):
  STATUS     = struct.pack('i', 0)
  ACTIVATE   = struct.pack('i', 1 | (1 << 16))
  DEACTIVATE = struct.pack('i', 1)
  INT_SIZE   = struct.calcsize('i')

  def __init__(self, socketfile):
    if socketfile[0] == '@': # abstract socket
      socketfile = '\x00' + socketfile[1:]
    self.socketfile = socketfile
    self.sock = None

  def status(self):
    return self._with_socket(self._status) == 2

  def activate(self):
    self._with_socket(self._command, self.ACTIVATE)

  def deactivate(self):
    self._with_socket(self._command, self.DEACTIVATE)

  def _error(self, e):
    estr = str(e).replace('"', r'\"')
    file = self.socketfile.replace('"', r'\"')
    vim.command('echohl WarningMsg | echo "fcitx.vim: socket %s error: %s" | echohl NONE' % (file, estr))

  def _connect(self):
    self.sock = sock = socket.socket(socket.AF_UNIX)
    sock.settimeout(0.5)
    try:
      sock.connect(self.socketfile)
      return True
    except (socket.error, socket.timeout) as e:
      self._error(e)
      return False

  def _with_socket(self, func, *args, **kwargs):
    # fcitx doesn't support connection reuse
    if not self._connect():
      return

    with contextlib.closing(self.sock):
      try:
        return func(*args, **kwargs)
      except (socket.error, socket.timeout, struct.error) as e:
        self._error(e)

  def _status(self):
    self.sock.send(self.STATUS)
    return struct.unpack('i', self.sock.recv(self.INT_SIZE))[0]

  def _command(self, cmd):
    self.sock.send(cmd)

Fcitx = FcitxComm(fcitxsocketfile)

def fcitx2en():
  if Fcitx.status():
    vim.command('let b:inputtoggle = 1')
    Fcitx.deactivate()

def fcitx2zh():
  if vim.eval('exists("b:inputtoggle")') == '1':
    if vim.eval('b:inputtoggle') == '1':
      Fcitx.activate()
      vim.command('let b:inputtoggle = 0')
  else:
    vim.command('let b:inputtoggle = 0')