#pylint: disable=too-many-public-methods,import-error,too-few-public-methods,missing-docstring,unused-variable
import os
import shutil
import tempfile
import unittest
from unittest.mock import patch
from gleetex import cachedconverter, image
from gleetex.caching import JsonParserException
from gleetex.image import  remove_all

def get_number_of_files(path):
   return len(os.listdir(path))

def mk_eqn(eqn, count=0, pos=(1,1)):
   """Create formula. Each formula must look like this:
   (eqn, pos, path, dsp, count) for self._convert_concurrently, this is a
   shorthand with mocking a few values."""
   return (pos, False, eqn)

def write(path, content='dummy'):
   with open(path, 'w', encoding='utf-8') as f:
       f.write(str(content))

class Tex2imgMock():
   """Could use a proper mock, but this one allows a bit more tricking."""
   def __init__(self, fmt):
       self.__format = fmt
       self.set_dpi = self.set_transparency = self.set_foreground_color \
               = self.set_background_color = lambda x: None # do nothing

   def create_dvi(self, dvi_fn):
       with open(dvi_fn, 'w') as f:
           f.write('dummy')

   def create_image(self, dvi_fn):
       if os.path.exists(dvi_fn):
           os.remove(dvi_fn)
       write(os.path.splitext(dvi_fn)[0] + '.' + self.__format.value)

   def convert(self, tx, basename):
       write(basename + '.tex', tx)
       dvi = basename + '.dvi'
       self.create_dvi(dvi)
       self.create_image(dvi)
       remove_all(dvi, basename + '.tex', basename + '.log', basename + '.aux')
       return {'depth': 9, 'height': 8, 'width': 7}

   def parse_log(self, _logdata):
       return {}


class TestCachedConverter(unittest.TestCase):
   #pylint: disable=protected-access
   def setUp(self):
       self.original_directory = os.getcwd()
       self.tmpdir = tempfile.mkdtemp()
       os.chdir(self.tmpdir)


   #pylint: disable=protected-access
   def tearDown(self):
       # restore static reference to converter
       cachedconverter.CachedConverter._converter = image.Tex2img
       os.chdir(self.original_directory)
       shutil.rmtree(self.tmpdir, ignore_errors=True)



   @patch('gleetex.image.Tex2img', Tex2imgMock)
   def test_that_subdirectory_is_created(self):
       c = cachedconverter.CachedConverter('subdirectory')
       formula = ({}, True, '\\textbf{FOO!}')
       c.convert_all([formula])
       # one directory exists
       self.assertEqual(get_number_of_files('.'), 1,
               "Found the following files, expected only 'subdirectory': " + \
               ', '.join(os.listdir('.')))
       # subdirectory contains 1 image and a cache
       self.assertEqual(get_number_of_files('subdirectory'), 2, "expected two"+\
           " files, found instead " + repr(os.listdir('subdirectory')))

   def test_that_unknown_options_trigger_exception(self):
       c = cachedconverter.CachedConverter('subdirectory')
       self.assertRaises(ValueError, c.set_option, 'cxzbiucxzbiuxzb', 'muh')

   def test_that_invalid_caches_trigger_error_by_default(self):
       with open('gladtex.cache', 'w') as f:
           f.write('invalid cache')
       with self.assertRaises(JsonParserException):
           c = cachedconverter.CachedConverter('')

   @patch('gleetex.image.Tex2img', Tex2imgMock)
   def test_that_invalid_caches_get_removed_if_specified(self):
       formulas = [mk_eqn('tau')]
       with open('gladtex.cache', 'w') as f:
           f.write('invalid cache')
       c = cachedconverter.CachedConverter('.', keep_old_cache=False)
       c.convert_all(formulas)
       # cache got overridden
       with open('gladtex.cache') as f:
           self.assertFalse('invalid' in f.read())

   @patch('gleetex.image.Tex2img', Tex2imgMock)
   def test_that_converted_formulas_are_cached(self):
       formulas = [mk_eqn('\\tau')]
       c = cachedconverter.CachedConverter('.')
       c.convert_all(formulas)
       self.assertTrue(c.get_data_for('\\tau', False))


   @patch('gleetex.image.Tex2img', Tex2imgMock)
   def test_that_file_names_are_correctly_picked(self):
       formulas = [mk_eqn('\\tau')]
       write('eqn000.svg')
       write('eqn001.svg')
       c = cachedconverter.CachedConverter('')
       to_convert = c._get_formulas_to_convert(formulas)
       self.assertTrue(len(to_convert), 1)
       self.assertEqual(to_convert[0][2], 'eqn002.svg')

   @patch('gleetex.image.Tex2img', Tex2imgMock)
   def test_that_all_converted_formulas_are_in_cache_and_meta_info_correct(self):
       formulas = [mk_eqn('a_{%d}' % i, pos=(i,i), count=i) for i in range(4)]
       c = cachedconverter.CachedConverter('.')
       c.convert_all(formulas)
       # expect all formulas and a gladtex cache to exist
       self.assertEqual(get_number_of_files('.'), len(formulas)+1,
               "present files:\n" + ', '.join(os.listdir('.')))
       for pos, dsp, formula in formulas:
           data = c.get_data_for(formula, False)
           self.assertEqual(data['pos'], {'depth': 9, 'height': 8, 'width': 7},
                   "expected the pos as defined in the dummy class")

   @patch('gleetex.image.Tex2img', Tex2imgMock)
   def test_that_inline_math_and_display_math_results_in_different_formulas(self):
       # two formulas, second is displaymath
       formula = r'\sum_{i=0}^n x_i'
       formulas = [((1,1), False, formula), ((3,1), True, formula)]
       c = cachedconverter.CachedConverter('.')
       c.convert_all(formulas)
       # expect all formulas and a gladtex cache to exist
       self.assertEqual(get_number_of_files('.'), len(formulas)+1,
               "present files:\n%s" % ', '.join(os.listdir('.')))