###############################################################################
##
## Copyright (C) 2011-2014, NYU-Poly.
## Copyright (C) 2006-2011, University of Utah. 
## All rights reserved.
## Contact: contact@vistrails.org
##
## This file is part of VisTrails.
##
## "Redistribution and use in source and binary forms, with or without 
## modification, are permitted provided that the following conditions are met:
##
##  - Redistributions of source code must retain the above copyright notice, 
##    this list of conditions and the following disclaimer.
##  - Redistributions in binary form must reproduce the above copyright 
##    notice, this list of conditions and the following disclaimer in the 
##    documentation and/or other materials provided with the distribution.
##  - Neither the name of the University of Utah nor the names of its 
##    contributors may be used to endorse or promote products derived from 
##    this software without specific prior written permission.
##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
## THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
## OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
## OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
## ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
##
###############################################################################
import sys
import copy
from datetime import datetime

from vistrails.core.data_structures.graph import Graph
from vistrails.core.system import time_strptime
from vistrails.db.versions.v0_5_0.domain import DBVistrail, DBAction, DBTag, DBModule, \
    DBConnection, DBPortSpec, DBFunction, DBParameter, DBLocation, DBAdd, \
    DBChange, DBDelete, DBAnnotation, DBPort

def convertDate(date):
    if date is not None and date != '':
        return datetime(*time_strptime(date, '%d %b %Y %H:%M:%S')[0:6])
    return datetime(1900, 1, 1)

def translateVistrail(_vistrail):
    vistrail = DBVistrail()
    for _action in _vistrail.db_get_actions():
#        print 'translating action %s' % _action.db_time
        functionName = 'translate%s%sAction' % \
            (_action.db_what[0].upper(), _action.db_what[1:])
        thisModule = sys.modules[__name__]
        action = getattr(thisModule, functionName)(_action)
        vistrail.db_add_action(action)
    for _tag in _vistrail.db_get_tags():
        tag = DBTag(time=_tag.db_time,
                    name=_tag.db_name)
        vistrail.db_add_tag(tag)

    convertIds(vistrail)
#     for action in vistrail.getActions():
#         print '%s %s' % (action.id, action.operations)
    vistrail.db_version = '0.5.0'
    return vistrail

def translateAddModuleAction(_action):
    operations = []
    for _module in _action.db_datas:
        module = DBModule(id=_module.db_id,
                          name=_module.db_name,
                          cache=1,
                          location=DBLocation(id=_module.db_id,
                                              x=_module.db_x,
                                              y=_module.db_y))
        module.db_location.relative = False
        operation = DBAdd(id=_action.db_time,
                          what='module',
                          objectId=_module.db_id,
                          data=module)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateAddConnectionAction(_action):
    operations = []
    for _connection in _action.db_datas:
        source = DBPort(id=_connection.db_id,
                        type='source',
                        moduleId=_connection.db_sourceId,
                        moduleName=_connection.db_sourceModule,
                        sig=_connection.db_sourcePort)
        destination = DBPort(id=_connection.db_id,
                             type='destination',
                             moduleId=_connection.db_destinationId,
                             moduleName=_connection.db_destinationModule,
                             sig=_connection.db_destinationPort)
        connection = DBConnection(id=_connection.db_id,
                                  ports=[source, destination])
        operation = DBAdd(id=_action.db_time,
                          what='connection',
                          objectId=_connection.db_id,
                          data=connection)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateChangeParameterAction(_action):
    operations = []
    for _set in _action.db_datas:
        parameter = DBParameter(id=_set.db_parameterId,
                                pos=_set.db_parameterId,
                                name=_set.db_parameter,
                                alias=_set.db_alias,
                                val=_set.db_value,
                                type=_set.db_type)
        function = DBFunction(id=_set.db_functionId,
                              pos=_set.db_functionId,
                              name=_set.db_function,
                              parameters=[parameter])
        operation = DBChange(id=_action.db_time,
                             what='function',
                             oldObjId=_set.db_functionId,
                             parentObjId=_set.db_moduleId,
                             parentObjType='module',
                             data=function)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateAddModulePortAction(_action):
    operations = []
    for _portSpec in _action.db_datas:
        # ids need to be checked
        portSpec = DBPortSpec(id=_portSpec.db_moduleId,
                              name=_portSpec.db_portName,
                              type=_portSpec.db_portType,
                              spec=_portSpec.db_portSpec)
        operation = DBAdd(id=_action.db_time,
                          what='portSpec',
                          objectId=(_portSpec.db_portName,
                                    _portSpec.db_portType),
                          parentObjId=_portSpec.db_moduleId,
                          parentObjType='module',
                          data=portSpec)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateChangeAnnotationAction(_action):
    operations = []
    for _annotation in _action.db_datas:
        if _annotation.db_key.strip() != '' or \
                _annotation.db_value.strip() != '':
            annotation = DBAnnotation(id=-1,
                                      key=_annotation.db_key,
                                      value=_annotation.db_value)
            operation = DBChange(id=_action.db_time,
                                 what='annotation',
                                 oldObjId=_annotation.db_key,
                                 parentObjId=_annotation.db_moduleId,
                                 parentObjType='module',
                                 data=annotation)
            operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateDeleteModuleAction(_action):
    operations = []
    for _module in _action.db_datas:
        operation = DBDelete(id=_action.db_time,
                             what='module',
                             objectId=_module.db_moduleId)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateDeleteConnectionAction(_action):
    operations = []
    for _connection in _action.db_datas:
        operation = DBDelete(id=_action.db_time,
                             what='connection',
                             objectId=_connection.db_connectionId)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateDeleteFunctionAction(_action):
    operations = []
    for _function in _action.db_datas:
        operation = DBDelete(id=_action.db_time,
                             what='function',
                             objectId=_function.db_functionId,
                             parentObjId=_function.db_moduleId,
                             parentObjType='module')
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateDeleteAnnotationAction(_action):
    operations = []
    for _annotation in _action.db_datas:
        operation = DBDelete(id=_action.db_time,
                             what='annotation',
                             objectId=_annotation.db_key)
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateDeleteModulePortAction(_action):
    operations = []
    for _portSpec in _action.db_datas:
        operation = DBDelete(id=_action.db_time,
                             what='portSpec',
                             objectId=(_portSpec.db_portName,
                                       _portSpec.db_portType),
                             parentObjId=_portSpec.db_moduleId,
                             parentObjType='module')
        operations.append(operation)

    action = DBAction(id=_action.db_time,
                      prevId=_action.db_parent,
                      date=convertDate(_action.db_date),
                      user=_action.db_user,
                      operations=operations)
    return action

def translateMoveModuleAction(_action):
    operations = []
    for _location in _action.db_datas:
        location = DBLocation(id=_location.db_id,