# Copyright (c) 2011, Enthought, Ltd.
# Author: Pietro Berkes <pberkes@enthought.com>
# License: Modified BSD license (2-clause)

from contextlib import contextmanager
from traits.has_traits import HasTraits
from traits.trait_types import Instance, Bool, Str, Int
import unicodedata
from traits.traits import Property
from traitsui.ui import UI
from pyanno.database import PyannoDatabase
from pyanno.modelBt import ModelBt
from pyanno.ui.database_view import DatabaseView
from pyanno.ui.model_data_view import ModelDataView
import os
import errno
import os.path
import pyanno

import logging
logger = logging.getLogger(__name__)


PYANNO_PATH_NAME = '.pyanno'
DATABASE_FILENAME = 'pyanno_results.db'


class PyannoApplication(HasTraits):

    database = Instance(PyannoDatabase)

    main_window = Instance(ModelDataView)

    database_window = Instance(DatabaseView)

    database_ui = Instance(UI)

    logging_level = Int(logging.INFO)

    pyanno_pathname = Str

    db_window_open = Property(Bool)
    def _get_db_window_open(self):
        return (self.database_ui is not None
                and self.database_ui.control is not None)


    def open(self):
        self._start_logging()
        self._open_pyanno_database()
        self._open_main_window()


    def close(self):
        self.database.close()
        logging.info('Closing pyAnno -- Goodbye!')


    def _start_logging(self):
        logging.basicConfig(level=logging.DEBUG)
        logging.info('Starting pyAnno')


    def _create_pyanno_directory(self):
        """Create a pyanno directort in the user's home if it is missing."""
        home_dir = os.getenv('HOME')
        self.pyanno_pathname = os.path.join(home_dir, PYANNO_PATH_NAME)
        try:
            os.makedirs(self.pyanno_pathname)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise


    def _open_pyanno_database(self):
        # database filename
        self._create_pyanno_directory()
        db_filename = os.path.join(self.pyanno_pathname,
                                   DATABASE_FILENAME)
        self.database = PyannoDatabase(db_filename)


    def _open_main_window(self):
        self.main_window = ModelDataView(application=self)

        model = ModelBt.create_initial_state(5)
        self.main_window.set_model(model)

        self.main_window.configure_traits()


    def open_database_window(self):
        if self.db_window_open:
            # windows exists, raise
            self.database_ui.control.Raise()
        else:
            # window was closed or not existent
            logger.debug('Open database window')
            database_window = DatabaseView(database=self.database,
                                           application=self)
            database_ui = database_window.edit_traits(kind='live')

            self.database_window = database_window
            self.database_ui = database_ui


    def close_database_window(self):
        # wx specific
        self.database_ui.control.Close()


    def update_window_from_database_record(self, record):
        """Update main window from pyanno database record.
        """
        self.main_window.set_from_database_record(record)


    def add_current_state_to_database(self):
        mdv = self.main_window

        # file name may contain unicode characters
        data_id = mdv.annotations_view.annotations_container.name
        if data_id is '':
            data_id = 'anonymous_annotations'
        elif type(data_id) is unicode:
            u_data_id = unicodedata.normalize('NFKD', data_id)
            data_id = u_data_id.encode('ascii','ignore')

        self.database.store_result(
            data_id,
            mdv.annotations_view.annotations_container,
            mdv.model,
            mdv.log_likelihood
        )

        if self.db_window_open:
            self.database_window.db_updated = True


    def _create_debug_database(self):
        """Create and populate a test database in a temporary file.
        """

        from tempfile import mktemp
        from pyanno.modelA import ModelA
        from pyanno.modelB import ModelB
        from pyanno.annotations import AnnotationsContainer

        # database filename
        tmp_filename = mktemp(prefix='tmp_pyanno_db_')
        db = PyannoDatabase(tmp_filename)

        def _create_new_entry(model, annotations, id):
            value = model.log_likelihood(annotations)
            ac = AnnotationsContainer.from_array(annotations, name=id)
            db.store_result(id, ac, model, value)

        # populate database
        model = ModelA.create_initial_state(5)
        annotations = model.generate_annotations(100)
        _create_new_entry(model, annotations, 'test_id')

        modelb = ModelB.create_initial_state(5, 8)
        _create_new_entry(modelb, annotations, 'test_id')

        annotations = model.generate_annotations(100)
        _create_new_entry(modelb, annotations, 'test_id2')

        self.database = db


@contextmanager
def pyanno_application(**traits):
    app = PyannoApplication(**traits)
    yield app
    app.close()



def main():
    """ Entry point for standalone testing/debugging. """

    app = PyannoApplication()
    app._create_debug_database()
    app._open_main_window()
    #app.open_database_window()
    app.close()

    return app

if __name__ == '__main__':
    app = main()

@@ -311,16 +311,51 @@
 roperty%0A
+from traitsui.message import error%0A
 from tra
@@ -620,16 +620,59 @@
 logging%0A
+from pyanno.util import PyannoValueError%0A%0A%0A
 logger =
@@ -3704,24 +3704,41 @@
 ,'ignore')%0A%0A
+        try:%0A    
         self
@@ -3769,24 +3769,28 @@
             
+    
 data_id,%0A   
@@ -3794,24 +3794,28 @@
             
+ 
+   
 mdv.annotati
@@ -3854,24 +3854,28 @@
             
+    
 mdv.model,%0A 
@@ -3873,16 +3873,20 @@
 .model,%0A
+    
         
@@ -3916,16 +3916,154 @@
         
+    )%0A        except PyannoValueError as e:%0A            logger.info(e)%0A            errmsg = e.args%5B0%5D%0A            error('Error: ' + errmsg
 )%0A%0A     

store result for conflicting annotations handled with modal dialog