import os
import shutil
import sys
import tempfile
import unittest

from openmdao.main.component import Component
from openmdao.main.datatypes.api import Float
from openmdao.main.factorymanager import get_signature
from openmdao.main.project import Project, project_from_archive, PROJ_FILE_EXT, \
    _filter_macro, ProjFinder, _match_insts, \
    load_project
from openmdao.util.fileutil import build_directory, onerror


class Multiplier(Component):
    rval_in = Float(iotype='in')
    rval_out = Float(iotype='out')
    mult = Float(iotype='in')

    def __init__(self):
        super(Multiplier, self).__init__()
        self.rval_in = 4.
        self.rval_out = 6.
        self.mult = 1.5

    def execute(self):
        self.rval_out = self.rval_in * self.mult


class ProjectTestCase(unittest.TestCase):
    def setUp(self):
        self.startdir = os.getcwd()
        self.tdir = tempfile.mkdtemp()
        os.chdir(self.tdir)

    def tearDown(self):
        try:
            shutil.rmtree(self.tdir, onerror=onerror)
        except:
            pass
        finally:
            os.chdir(self.startdir)

    def _fill_project(self, proj):
        proj.command("top = set_as_top(create('openmdao.main.assembly.Assembly'))")
        proj.command('top.add("comp1", create("openmdao.main.test.test_project.Multiplier"))')
        proj.command('top.add("comp2", create("openmdao.main.test.test_project.Multiplier"))')

        proj.command("top.driver.workflow.add(['comp1', 'comp2'])")

        proj.command('top.comp1.mult = 2.0')
        proj.command('top.comp2.mult = 4.0')
        proj.command("top.connect('comp1.rval_out', 'comp2.rval_in')")
        proj.command("top.comp1.rval_in = 5.0")

    def test_project_export_import(self):
        proj = Project(os.path.join(self.tdir, 'proj1'))
        self.assertEqual(proj.config.items('info'),
                         [('version', '0'), ('description', '')])
        new_info = [('version', 'stinky'), ('description', 'Frobozz rulz!')]
        proj.set_info(dict(new_info))
        proj.activate()
        self._fill_project(proj)

        proj.export(destdir=self.tdir)
        proj.deactivate()

        newproj = project_from_archive(os.path.join(self.tdir,
                                                    'proj1%s' % PROJ_FILE_EXT),
                                       proj_name='proj2',
                                       dest_dir=self.tdir)

        self.assertEqual(newproj.path, os.path.join(self.tdir, 'proj2'))
        self.assertEqual(newproj.config.items('info'), new_info)

        try:
            newproj = project_from_archive(os.path.join(self.tdir,
                                                        'proj1%s' % PROJ_FILE_EXT),
                                           dest_dir=self.tdir)
        except Exception, err:
            self.assertTrue(str(err).endswith(' already exists'))
        else:
            self.fail("Exception expected")

    def test_using(self):
        proj = Project('a_proj')
        proj.activate()
        self._fill_project(proj)
        top = proj.get('top')
        top.run()