#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
# with Numenta, Inc., for a separate license for this software code, the
# following terms and conditions apply:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero Public License for more details.
#
# You should have received a copy of the GNU Affero Public License
# along with this program.  If not, see http://www.gnu.org/licenses.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

from copy import copy
import os
import shutil
from StringIO import StringIO
import sys
import tempfile
import unittest2 as unittest
import uuid
from pkg_resources import resource_filename

from mock import Mock, patch
from pkg_resources import resource_filename
from xml.parsers.expat import ExpatError
# ParseError not present in xml module for python2.6
try:
    from xml.etree.ElementTree import ParseError
except ImportError:
    from xml.parsers.expat import ExpatError as ParseError

import nupic
import nupic.support.configuration_custom as configuration

import configuration_test



class ConfigurationCustomTest(unittest.TestCase):

  def setUp(self):

    if "NTA_DYNAMIC_CONF_DIR" in os.environ:
      # Remove it to make sure our in-proc tests won't accidentally
      # mess with actual files
      oldNtaDynamicConfDir = os.environ["NTA_DYNAMIC_CONF_DIR"]
      del os.environ["NTA_DYNAMIC_CONF_DIR"]
      self.addCleanup(os.environ.update,
                      dict(NTA_DYNAMIC_CONF_DIR=oldNtaDynamicConfDir))

    self.files = dict()

    tmpDir = tempfile.mkdtemp()
    self.addCleanup(shutil.rmtree, tmpDir)


    with open(os.path.join(tmpDir, 'nupic-default.xml-unittest'), 'w') as fp:
      with open(resource_filename(__name__, 'conf/nupic-default.xml')) as inp:
        fp.write(inp.read())
        self.files['nupic-default.xml'] = fp.name

    with open(os.path.join(tmpDir, 'nupic-site.xml-unittest'), 'w') as fp:
      with open(resource_filename(__name__, 'conf/nupic-site.xml')) as inp:
        fp.write(inp.read())
        self.files['nupic-site.xml'] = fp.name

    with open(os.path.join(tmpDir, 'nupic-custom.xml'), 'w') as fp:
      with open(resource_filename(__name__, 'conf/nupic-custom.xml')) as inp:
        fp.write(inp.read())
        self.files['nupic-custom.xml'] = fp.name

    self.customParam = 'nupic.custom.hello'
    self.customValue = 'world'

    configuration.Configuration.clear()



  ####################################################################
  # Custom Configuration Tests
  # Todo: Share tests between two configuration_test files
  ####################################################################

  @patch.object(configuration.os, 'environ', spec=dict)
  @patch.object(configuration.Configuration, 'findConfigFile',
                spec=configuration.Configuration.findConfigFile)
  def testCustomFileCreated(self, findConfigFile, environ):
    environ.__getitem__.side_effect = dict(
      NTA_DYNAMIC_CONF_DIR=os.path.dirname(self.files['nupic-custom.xml'])).get
    environ.get.return_value = None
    findConfigFile.side_effect = self.files.get
    configuration.Configuration.clear()
    configuration.Configuration.setCustomProperty('param', 'val')
    self.assertTrue(os.path.exists(self.files['nupic-custom.xml']))

  @patch.object(configuration.os, 'environ', spec=dict)
  @patch.object(configuration.Configuration, 'findConfigFile',
                spec=configuration.Configuration.findConfigFile)
  def testGet(self, findConfigFile, environ):
    environ.get.return_value = None
    findConfigFile.side_effect = self.files.get
    configuration.Configuration.clear()
    with open(self.files['nupic-custom.xml'], 'w') as fp:
      fp.write('\n'.join((
          '<?xml version="1.0"?>',
          '<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>',
          '<configuration>',
          '  <property>',
          '    <name>'+self.customParam+'</name>',
          '    <value>'+self.customValue+'</value>',
          '  </property>',
          '</configuration>')))

    self.assertEqual(
      configuration.Configuration.get(self.customParam),
      self.customValue)


  @patch.object(configuration.os, 'environ', spec=dict)
  @patch.object(configuration.Configuration, 'findConfigFile',
                spec=configuration.Configuration.findConfigFile)
  def testSetCustomProperty(self, findConfigFile, environ):
    environ.__getitem__.side_effect = dict(
      NTA_DYNAMIC_CONF_DIR=os.path.dirname(self.files['nupic-custom.xml'])).get
    environ.get.return_value = None
    configuration.Configuration.clear()
    findConfigFile.side_effect = self.files.get
    with open(self.files['nupic-custom.xml'], 'w') as fp:
      fp.write('\n'.join((
          '<?xml version="1.0"?>',
          '<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>',
          '<configuration>',
          '  <property>',
          '    <name>' + self.customParam + '</name>',
          '    <value>' + self.customValue + '</value>',
          '  </property>',
          '</configuration>')))
    configuration.Configuration.setCustomProperty('PersistProp', 'PersistVal')
    self.assertEqual(
      configu
ration.Configuration.get('PersistProp'),'PersistVal')
    configuration.Configuration
.clear()
    self.assertEqual(
      configuration.Configuration.get('PersistProp'),'PersistVal')


  @patch.object(configuration.os, 'environ', spec=dict)
  @patch.object(configuration.Configuration, 'findConfigFile',
                spec=configuration.Configuration.findConfigFile)
  def testSetCustomProperties(self, findConfigFile, environ):
    environ.__getitem__.side_effect = dict(
      NTA_DYNAMIC_CONF_DIR=os.path.dirname(self.files['nupic-custom.xml'])).get
    environ.get.return_value = None
    findConfigFile.side_effect = self.files.get
    with open(self.files['nupic-custom.xml'], 'w') as fp:
      fp.write('\n'.join((
          '<?xml version="1.0"?>',
          '<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>',
          '<configuration>',
          '  <property>',
          '    <name>' + self.customParam + '</name>',
          '    <value>' + self.customValue + '</value>',
          '  </property>',
          '</configuration>')))

    configuration.Configuration.clear()
    originalProps = copy(configuration.Configuration.dict())

    configuration.Configuration.setCustomProperties(
      {'PersistProp' : 'PersistVal', 'apple' : 'pear'})

    expectedProps = {'PersistProp' : 'PersistVal', 'apple' : 'pear'}
    expectedProps.update(originalProps)
    self.assertEqual(configuration.Configuration.dict(), expectedProps)
    configuration.Configuration.clear()
    self.assertEqual(configuration.Configuration.dict(), expectedProps)


  @patch.object(configuration.os, 'environ', spec=dict)
  @patch.object(configuration.Configuration, 'findConfigFile',
                spec=configuration.Configuration.findConfigFile)
  def testDictWithTemp(self, findConfigFile, environ):
    environ.get.return_value = None
    findConfigFile.side_effect = self.files.get
    configuration.Configuration.clear()
    with open(self.files['nupic-custom.xml'], 'w') as fp:
      fp.write('\n'.join((
          '<?xml version="1.0"?>',
          '<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>',
          '<configuration>',
          '  <property>',
          '    <name>param</name>',
          '    <value>value</value>',
          '  </property>',
          '  <property>',
          '    <name>param2</name>',
          '    <value>value2</value>',
          '  </property>',
          '</configuration>')))

    customDict = configuration.Configuration.