#
# Copyright 2014 ETH Zuerich, Scientific IT Services
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# MasterDataRegistrationTransaction Class
import definitions
import definitionsVoc
import os
import copy
import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.DataType as DataType

##
## Globals
##
vocabulariesCache = {};
propertiesCache = {};
samplesCache = {};
tr = service.transaction()

##
## API Facade
##
def createVocabularyWithTerms(vocabularyCode, terms):
    vocabulary = tr.createNewVocabulary(vocabularyCode);
    vocabulary.setChosenFromList(True);
    addTerms(vocabulary, terms);
    vocabulariesCache[vocabularyCode] = vocabulary;
    
def addTerms(vocabulary, terms):
    for term in terms:
        addTermWithLabel(vocabulary, term[0], term[1])
    
def addTermWithLabel(vocabulary, termCode, termLabel):
    newTerm = tr.createNewVocabularyTerm(termCode);
    newTerm.setLabel(termLabel);
    vocabulary.addTerm(newTerm);
    
def createSampleTypeWithProperties(sampleTypeCode, description, properties):
    newSampleType = tr.getOrCreateNewSampleType(sampleTypeCode);
    newSampleType.setDescription(description);
    newSampleType.setShowParents(True);
    newSampleType.setAutoGeneratedCode(True);
    newSampleType.setGeneratedCodePrefix(sampleTypeCode[:3]);
    addProperties(newSampleType, properties);
    samplesCache[sampleTypeCode] = newSampleType;
    
def createDataSetTypeWithProperties(dataSetCode, description, properties):
    newDataSet = tr.getOrCreateNewDataSetType(dataSetCode);
    newDataSet.setDescription(description);
    addProperties(newDataSet, properties);
    
def createExperimentTypeWithProperties(experimentTypeCode, description, properties):
    newExperiment = tr.getOrCreateNewExperimentType(experimentTypeCode);
    newExperiment.setDescription(description);
    addProperties(newExperiment, properties);

def getSampleType(sampleTypeCode):
    sampleType = None
    if sampleTypeCode in samplesCache:
        sampleType = samplesCache[sampleTypeCode];
    else:
        sampleType = tr.getSampleType(sampleTypeCode)
        samplesCache[sampleTypeCode] = sampleType;
    return sampleType;
            
def addPropertiesToSamples(sampleTypeCodes, properties):
    for sampleTypeCode in sampleTypeCodes:
        sampleType = getSampleType(sampleTypeCodes);
        addProperties(sampleType, properties);
    
def addProperties(entity, properties):
    for property in properties:
        addProperty(entity, property[0], property[1], property[2], property[3], property[4], property[5], property[6], property[7], property[8], None);
    
def addProperty(entity, propertyCode, section, propertyLabel, dataType, vocabularyCode, propertyDescription, managedScript, dynamicScript, isMandatory, position):
    property = None;
    
    if propertyCode in propertiesCache:
        property = propertiesCache[propertyCode];
    else:
        property = createProperty(propertyCode, dataType, propertyLabel, propertyDescription, vocabularyCode);
    
    propertyAssignment = tr.assignPropertyType(entity, property);
    propertyAssignment.setSection(section);
    propertyAssignment.setMandatory(isMandatory);
    if position is not None:
        propertyAssignment.setPositionInForms(position);
    if managedScript != None:
        propertyAssignment.setManaged(True);
        propertyAssignment.setShownEdit(True);
        propertyAssignment.setScriptName(managedScript);
    if dynamicScript != None:
        propertyAssignment.setDynamic(True);
        propertyAssignment.setShownEdit(True);
        propertyAssignment.setScriptName(dynamicScript);

def createProperty(propertyCode, dataType, propertyLabel, propertyDescription, vocabularyCode):
    property = tr.getOrCreateNewPropertyType(propertyCode, dataType);
    property.setDescription(propertyDescription);
    property.setLabel(propertyLabel);
    propertiesCache[propertyCode] = property;
    if dataType == DataType.CONTROLLEDVOCABULARY:
        property.setVocabulary(vocabulariesCache[vocabularyCode]);
    return property;

def addStorageGroups(numGroups, sampleType):
    for storageIdx in range(1,(numGroups + 1)):
        storageGroup = definitions.getStorageGroupDefinition();
        for property in storageGroup:
            property[0] = property[0] + "_" + str(storageIdx);
            property[1] = property[1] + "_" + str(storageIdx);
            property[5] = property[5] + "_" + str(storageIdx);
        addPropertiesToSamples([sampleType], storageGroup);

def findAssignment(entityType, propertyType):
    for assignment in tr.listPropertyAssignments():
        if assignment.getEntityKind().equals(entityType.getEntityKind()) and assignment.getEntityTypeCode() == entityType.getCode() and assignment.getPropertyTypeCode() == propertyType.getCode():
            return assignment;
    return None;
    
def addBoxSizeProperty(numGroups, sampleTypeCode):
    sampleType = getSampleType(sampleTypeCode)
    for storageIdx in range(1,(numGroups + 1)):
        property = ["STORAGE_BOX_SIZE",     "Physical Storage",        "box size",         DataType.CONTROLLEDVOCABULARY,      "STORAGE_BOX_SIZE",   "Storage Box size",   None, None, False];
        property[0] = property[0] + "_" + str(storageIdx);
        property[1] = property[1] + "_" + str(storageIdx);
        property[5] = property[5] + "_" + str(storageIdx);
        #Resolve Position
        position = None
        propertyTypeCode = "STORAGE_USER" + "_" + str(storageIdx);
        propertyType = tr.getPropertyType(propertyTypeCode);
        assigments = tr.listPropertyAssignments();
        assigment = findAssignment(sampleType, propertyType);
        if storageIdx == 1:
            position = assigment.getPositionInForms();
        else:
            position = assigment.getPositionInForms() + storageIdx - 1;
        addProperty(sampleType, property[0], property[1], property[2], property[3], property[4], property[5], property[6], property[7], property[8], position);

#Valid Script Types: DYNAMIC_PROPERTY, MANAGED_PROPERTY, ENTITY_VALIDATION 
def createScript(path, name, description, scriptType, entityType):
    scriptAsString = open(path, 'r').read();
    script = tr.getOrCreateNewScript(name);
    script.setName(name);
    script.setDescription(description);
    script.setScript(scriptAsString);
    script.setScriptType(scriptType);
    script.setEntityForScript(entityType);
    return script;

##
## Vocabulary Types
##
createVocabularyWithTerms("STORAGE_BOX_SIZE", definitionsVoc.vocabularyDefinitions["STORAGE_BOX_SIZE"]);

##
## New Position Property
##
addBoxSizeProperty(definitions.numberOfStorageGroups, "ANTIBODY");
addBoxSizeProperty(definitions.numberOfStorageGroups, "CELL");
addBoxSizeProperty(definitions.numberOfStorageGroups, "STRAIN");
addBoxSizeProperty(definitions.numberOfStorageGroups, "PLASMID");
addBoxSizeProperty(definitions.numberOfStorageGroups, "OLIGO");
