'''
Created on Mar 18, 2016
This module is responsible for converting the tasks csv file to tasks objects and sends them out to the storage service
@author: auerbach
'''
import csv
import io
from SuperGLU.Core.MessagingGateway import BaseService
from SuperGLU.Services.StudentModel.PersistentData import LearningTask, SerializableAssistmentsItem, DBAssistmentsItem, DBTask
from SuperGLU.Core.FIPA.SpeechActs import INFORM_ACT, REQUEST_ACT
from SuperGLU.Util.ErrorHandling import logInfo
from SuperGLU.Core.Messaging import Message
from SuperGLU.Services.StorageService.Storage_Service_Interface import VALUE_VERB, STORAGE_SERVICE_NAME
from SuperGLU.Util.Serialization import serializeObject
from SuperGLU.Core.MessagingDB import ELECTRONIX_TUTOR_TASK_UPLOAD_VERB


CSV_READER_SERVICE_NAME = "CSV Reader Service"
TASKS_OBJECT = "tasks"

SYSTEM_COL_NAME = "System"
TASK_ID_COL_NAME = "Problem ID (Name)"
TASK_DISPLAY_COL_NAME = "Problem Display Name"
DESCRIPTION_COL_NAME = "Description"
TOPIC_COL_NAME = "Topic"
TYPE_COL_NAME = "Type"
DATE_COL_NAME = "Curriculum Week+Day"
BASE_URL_COL_NAME = "Base Link (Original)"
KC_SET_COL_NAME = "KC Set"
ASSISTMENTS_PROB_ID_COL_NAME = "ASSISTments Problem ID (Single Item)"
ASSISTMENTS_SET_ID_COL_NAME = "ASSISTments Problem Set ID"
ASSISTMENTS_SET_NAME_COL_NAME = "ASSISTments Problem Set Name"
ASSISTMENTS_ASSIGN_COL_NAMES =("ASSISTments Assign 1 URL", "ASSISTments Assign 2 URL",
                               "ASSISTments Set 3 URL")
ENABLED_COL_NAME = "Enabled"

class CSVReader (BaseService):
    
    LINE_DELIMITER = '\n'
    CELL_DELIMITER = ','
    PIPE_DELIMITER = '|||'
    
    def receiveMessage(self, msg):
        #depending on the content of the message react differently
        #logInfo('Entering CSVReader.receiveMessage', 5)
        
        reply = None
        #Only considering 
        if msg.getSpeechAct() == INFORM_ACT:
        
            if msg.getVerb() == ELECTRONIX_TUTOR_TASK_UPLOAD_VERB:
                logInfo('{0} is processing a {1},{2} message'.format(CSV_READER_SERVICE_NAME, ELECTRONIX_TUTOR_TASK_UPLOAD_VERB, INFORM_ACT), 4)
                csvString = msg.getResult()
                taskList = self.processCSVFile(csvString)
                print("STORAGE SERVICE NAME: %s"%(STORAGE_SERVICE_NAME))
                reply = Message(STORAGE_SERVICE_NAME, VALUE_VERB, TASKS_OBJECT, taskList)
        
        if msg.getSpeechAct() == REQUEST_ACT:
            if msg.getVerb() == ELECTRONIX_TUTOR_TASK_UPLOAD_VERB:
                dbtaskList = DBTask.find_all()
                dbassistmentItemsList = DBAssistmentsItem.find_all()
                
                for dbTask in dbtaskList:
                    if dbTask.assistmentsItemId is not None and dbTask.assistmentsItemId is not '':
                        for dbassistmentsItem in dbassistmentItemsList:
                            if  dbassistmentsItem.id == dbTask.assistmentsItemId:
                                dbTask.assistmentsItemCache = dbassistmentsItem
                                break
                
                taskList = [x.toSerializable() for x in dbtaskList]
                reply = Message(CSV_READER_SERVICE_NAME, ELECTRONIX_TUTOR_TASK_UPLOAD_VERB, None, taskList, INFORM_ACT, msg.getContext())
        
        if reply is not None:
            logInfo('{0} is broadcasting a {1}, {2} message'.format(CSV_READER_SERVICE_NAME, INFORM_ACT, VALUE_VERB), 4)
            self.sendMessage(reply)

    def hasCellData(self, s):
        return s is not None and s != ''
    
    def processCSVFile(self, csvString):
        #List of strings
        dictLines = csv.DictReader(io.StringIO(csvString))
        lines = [a for a in dictLines]
        
        relatedTasks = dict()
        #list of tasks
        result = []

        for row in lines:
            # Extract Row Data
            systemId = row.get(SYSTEM_COL_NAME, '')
            taskId = row.get(TASK_ID_COL_NAME, '')
            taskDisplayName = row.get(TASK_DISPLAY_COL_NAME, '')
            description = row.get(DESCRIPTION_COL_NAME, '')
            baseURL = row.get(BASE_URL_COL_NAME, '')
            assistmentsItemId = row.get(ASSISTMENTS_PROB_ID_COL_NAME, '') 
            assistmentsSetId = row.get(ASSISTMENTS_SET_ID_COL_NAME, '')
            assistmentsSetName = row.get(ASSISTMENTS_SET_NAME_COL_NAME, '')
            kcCell = row.get(KC_SET_COL_NAME, '')
                
            isEnabled = True
            if row.get(ENABLED_COL_NAME, 'True') == 'FALSE':
                isEnabled = False
        
            if isEnabled and (self.hasCellData(taskId) or self.hasCellData(taskDisplayName)):
                # Create the Task
                # logInfo('{0} is constructing the next serializable task object'.format(CSV_READER_SERVICE_NAME), 5)
                task = LearningTask()
                task._aliasIds = []
                task._system = systemId
                # logInfo('{0} is extracting the knowledge components'.format(CSV_READER_SERVICE_NAME), 5)
                task._kcs = [a for a in kcCell.split(self.PIPE_DELIMITER) if a != '']

                task._taskId = taskId
                task._name = taskDisplayName
                if not self.hasCellData(taskDisplayName):
                    task._name = task._taskId
                elif not self.hasCellData(taskId):
                    task._taskId = taskId

                task._displayName = taskDisplayName  
                
                if self.hasCellData(description):
                    task._description = description
                else:
                    task._description = task._name
                
                task._aliasIds.append(taskId)
                task._baseURL = baseURL
                
                #if there is an assismentsItem associated with this task
                if self.hasCellData(assistmentsItemId):
                    assistmentsItem = SerializableAssistmentsItem()
                    assistmentsItem._itemId = assistmentsItemId
                    assistmentsItem._problemSetId = assistmentsSetId
                    assistmentsItem._problemSetName = assistmentsSetName
                    assistmentsItem._assignments = []
                    logInfo('{0} is checking for assistments data'.format(CSV_READER_SERVICE_NAME), 5)
                    for colName in ASSISTMENTS_ASSIGN_COL_NAMES:
                        colData = row.get(colName, '')
                        if self.hasCellData(colData):
                            assistmentsItem._assignments.append(colData)
                    task._assistmentsItem = assistmentsItem
                else:
                    task._assistmentsItem = None
                
                #this could cause performance trouble so only use this log if you need to.
                #logInfo('{0} constructed task: {1}'.format(CSV_READER_SERVICE_NAME, serializeObject(task)), 5)
                # logInfo('{0} constructed task with name: {1}'.format(CSV_READER_SERVICE_NAME, task._name), 5)
                if isEnabled:
                    result.append(task)
                    #make additional tasks to represent combined tasks
                    if (task._assistmentsItem):
                        if (task._assistmentsItem._problemSetId not in relatedTasks):
                            relatedTasks[task._assistmentsItem._problemSetId] = []
                        relatedTasks[task._assistmentsItem._problemSetId].append(task)
                    
        
        for key in relatedTasks.keys():
            relatedTaskList = relatedTasks[key]
            if len(relatedTaskList) > 1:
                collectedTask = LearningTask()

                collectedTask._ids = []
                #collectedTask._ids.append()#What's going on here?
                
                kcSet = set()
                assignmentSet = set()
                collectedAssistmentsItem = SerializableAssistmentsItem()
                
                for relatedTask in relatedTaskList:
                    relatedTask._canBeRecommendedIndividually = False
                    # Subtask ids instead of ids field
                    collectedTask._subtasks.append(relatedTask._taskId)
                    
                    if len(collectedTask._ids) == 0:
                        collectedTask._ids.append(relatedTask._taskId)
                    else:
                        collectedTask._ids[0] += "~" + relatedTask._taskId
                    
                    if not collectedTask._name:
                        collectedTask._name = relatedTask._name
                    if not collectedTask._baseURL:
                        collectedTask._baseURL = relatedTask._baseURL
                    if not collectedTask._description:
                        collectedTask._description = relatedTask._description
                    if not collectedAssistmentsItem._itemId:
                        collectedAssistmentsItem._itemId = relatedTask._assistmentsItem._itemId
                    if not collectedAssistmentsItem._problemSetId:
                        collectedAssistmentsItem._problemSetId = relatedTask._assistmentsItem._problemSetId
                    if not collectedAssistmentsItem._problemSetName:
                        collectedAssistmentsItem._problemSetName = relatedTask._assistmentsItem._problemSetName 
                    # Add all the data
                    
                    for kc in relatedTask._kcs:
                        kcSet.add(kc)
                    
                    if relatedTask._assistmentsItem is not None:
                        for assignment in relatedTask._assistmentsItem._assignments:
                            assignmentSet.add(assignment)
                    
                
                collectedTask._kcs = list(kcSet) # This is the complete set accumulated from all subtasks
                collectedAssistmentsItem._assignments = list(assignmentSet)# The assignments inside of this should be the set of all non-duplicate, non-empty ASSISTments assignments from the subtasks
                
                collectedTask._assistmentsItem = collectedAssistmentsItem
                    
                result.append(collectedTask)

        
        logInfo('Exiting CSVReader.processCSVFile', 4)    
        return result
            

'''
Created on Mar 18, 2016
This module is responsible for converting the tasks csv file to tasks objects and sends them out to the storage service
@author: auerbach
'''
import csv
import io
from SuperGLU.Core.MessagingGateway import BaseService
from SuperGLU.Services.StudentModel.PersistentData import LearningTask, SerializableAssistmentsItem, DBAssistmentsItem, DBTask
from SuperGLU.Core.FIPA.SpeechActs import INFORM_ACT, REQUEST_ACT
from SuperGLU.Util.ErrorHandling import logInfo
from SuperGLU.Core.Messaging import Message
from SuperGLU.Services.StorageService.Storage_Service_Interface import VALUE_VERB, STORAGE_SERVICE_NAME
from SuperGLU.Util.Serialization import serializeObject
from SuperGLU.Core.MessagingDB import ELECTRONIX_TUTOR_TASK_UPLOAD_VERB


CSV_READER_SERVICE_NAME = "CSV Reader Service"
TASKS_OBJECT = "tasks"

SYSTEM_COL_NAME = "System"
TASK_ID_COL_NAME = "Problem ID (Name)"
TASK_DISPLAY_COL_NAME = "Problem Display Name"
DESCRIPTION_COL_NAME = "Description"
TOPIC_COL_NAME = "Topic"
TYPE_COL_NAME = "Type"
DATE_COL_NAME = "Curriculum Week+Day"
BASE_URL_COL_NAME = "Base Link (Original)"
KC_SET_COL_NAME = "KC Set"
ASSISTMENTS_PROB_ID_COL_NAME = "ASSISTments Problem ID (Single Item)"
ASSISTMENTS_SET_ID_COL_NAME = "ASSISTments Problem Set ID"
ASSISTMENTS_SET_NAME_COL_NAME = "ASSISTments Problem Set Name"
ASSISTMENTS_ASSIGN_COL_NAMES =("ASSISTments Assign 1 URL", "ASSISTments Assign 2 URL",
                               "ASSISTments Set 3 URL")
ENABLED_COL_NAME = "Enabled"

class CSVReader (BaseService):
    
    LINE_DELIMITER = '\n'
    CELL_DELIMITER = ','
    PIPE_DELIMITER = '|||'
    
    def receiveMessage(self, msg):
        #depending on the content of the message react differently
        #logInfo('Entering CSVReader.receiveMessage', 5)
        
        reply = None
        #Only considering 
        if msg.getSpeechAct() == INFORM_ACT:
        
            if msg.getVerb() == ELECTRONIX_TUTOR_TASK_UPLOAD_VERB:
                logInfo('{0} is processing a {1},{2} message'.format(CSV_READER_SERVICE_NAME, ELECTRONIX_TUTOR_TASK_UPLOAD_VERB, INFORM_ACT), 4)
                csvString = msg.getResult()
                taskList = self.processCSVFile(csvString)
                print("STORAGE SERVICE NAME: %s"%(STORAGE_SERVICE_NAME))
                reply = Message(STORAGE_SERVICE_NAME, VALUE_VERB, TASKS_OBJECT, taskList)
        
        if msg.getSpeechAct() == REQUEST_ACT:
            if msg.getVerb() == ELECTRONIX_TUTOR_TASK_UPLOAD_VERB:
                dbtaskList = DBTask.find_all()
                dbassistmentItemsList = DBAssistmentsItem.find_all()
                
                for dbTask in dbtaskList:
                    if dbTask.assistmentsItemId is not None and dbTask.assistmentsItemId is not '':
                        for dbassistmentsItem in dbassistmentItemsList:
                            if  dbassistmentsItem.id == dbTask.assistmentsItemId:
                                dbTask.assistmentsItemCache = dbassistmentsItem
                                break
                
                taskList = [x.toSerializable() for x in dbtaskList]
                reply = Message(CSV_READER_SERVICE_NAME, ELECTRONIX_TUTOR_TASK_UPLOAD_VERB, None, taskList, INFORM_ACT, msg.getContext())
        
        if reply is not None:
            logInfo('{0} is broadcasting a {1}, {2} message'.format(CSV_READER_SERVICE_NAME, INFORM_ACT, VALUE_VERB), 4)
            self.sendMessage(reply)

    def hasCellData(self, s):
        return s is not None and s != ''
    
    def processCSVFile(self, csvString):
        #List of strings
        dictLines = csv.DictReader(io.StringIO(csvString))
        lines = [a for a in dictLines]
        
        relatedTasks = dict()
        #list of tasks
        result = []

        for row in lines:
            # Extract Row Data
            systemId = row.get(SYSTEM_COL_NAME, '')
            taskId = row.get(TASK_ID_COL_NAME, '')
            taskDisplayName = row.get(TASK_DISPLAY_COL_NAME, '')
            description = row.get(DESCRIPTION_COL_NAME, '')
            baseURL = row.get(BASE_URL_COL_NAME, '')
            assistmentsItemId = row.get(ASSISTMENTS_PROB_ID_COL_NAME, '') 
            assistmentsSetId = row.get(ASSISTMENTS_SET_ID_COL_NAME, '')
            assistmentsSetName = row.get(ASSISTMENTS_SET_NAME_COL_NAME, '')
            kcCell = row.get(KC_SET_COL_NAME, '')
                
            isEnabled = True
            if row.get(ENABLED_COL_NAME, 'True') == 'FALSE':
                isEnabled = False
        
            if isEnabled and (self.hasCellData(taskId) or self.hasCellData(taskDisplayName)):
                # Create the Task
                # logInfo('{0} is constructing the next serializable task object'.format(CSV_READER_SERVICE_NAME), 5)
                task = LearningTask()
                task._aliasIds = []
                task._system = systemId
                # logInfo('{0} is extracting the knowledge components'.format(CSV_READER_SERVICE_NAME), 5)
                task._kcs = [a for a in kcCell.split(self.PIPE_DELIMITER) if a != '']

                task._taskId = taskId
                task._name = taskDisplayName
                if not self.hasCellData(taskDisplayName):
                    task._name = task._taskId
                elif not self.hasCellData(taskId):
                    task._taskId = taskId

                task._displayName = taskDisplayName  
                
                if self.hasCellData(description):
                    task._description = description
                else:
                    task._description = task._name
                
                task._aliasIds.append(taskId)
                task._baseURL = baseURL
                
                #if there is an assismentsItem associated with this task
                if self.hasCellData(assistmentsItemId):
                    assistmentsItem = SerializableAssistmentsItem()
                    assistmentsItem._itemId = assistmentsItemId
                    assistmentsItem._problemSetId = assistmentsSetId
                    assistmentsItem._problemSetName = assistmentsSetName
                    assistmentsItem._assignments = []
                    logInfo('{0} is checking for assistments data'.format(CSV_READER_SERVICE_NAME), 5)
                    for colName in ASSISTMENTS_ASSIGN_COL_NAMES:
                        colData = row.get(colName, '')
                        if self.hasCellData(colData):
                            assistmentsItem._assignments.append(colData)
                    task._assistmentsItem = assistmentsItem
                else:
                    task._assistmentsItem = None
                
                #this could cause performance trouble so only use this log if you need to.
                #logInfo('{0} constructed task: {1}'.format(CSV_READER_SERVICE_NAME, serializeObject(task)), 5)
                # logInfo('{0} constructed task with name: {1}'.format(CSV_READER_SERVICE_NAME, task._name), 5)
                if isEnabled:
                    result.append(task)
                    #make additional tasks to represent combined tasks
                    if (task._assistmentsItem):
                        if (task._assistmentsItem._problemSetId not in relatedTasks):
                            relatedTasks[task._assistmentsItem._problemSetId] = []
                        relatedTasks[task._assistmentsItem._problemSetId].append(task)
                    
        
        for key in relatedTasks.keys():
            relatedTaskList = relatedTasks[key]
            if len(relatedTaskList) > 1:
                collectedTask = LearningTask()

                collectedTask._ids = []
                #collectedTask._ids.append()#What's going on here?
                
                kcSet = set()
                assignmentSet = set()
                collectedAssistmentsItem = SerializableAssistmentsItem()
                
                for relatedTask in relatedTaskList:
                    relatedTask._canBeRecommendedIndividually = False
                    # Subtask ids instead of ids field
                    collectedTask._subtasks.append(relatedTask._taskId)
                    
                    if len(collectedTask._ids) == 0:
                        collectedTask._ids.append(relatedTask._taskId)
                    else:
                        collectedTask._ids[0] += "~" + relatedTask._taskId
                    
                    if not collectedTask._name:
                        collectedTask._name = relatedTask._name
                    if not collectedTask._baseURL:
                        collectedTask._baseURL = relatedTask._baseURL
                    if not collectedTask._description:
                        collectedTask._description = relatedTask._description
                    if not collectedAssistmentsItem._itemId:
                        collectedAssistmentsItem._itemId = relatedTask._assistmentsItem._itemId
                    if not collectedAssistmentsItem._problemSetId:
                        collectedAssistmentsItem._problemSetId = relatedTask._assistmentsItem._problemSetId
                    if not collectedAssistmentsItem._problemSetName:
                        collectedAssistmentsItem._problemSetName = relatedTask._assistmentsItem._problemSetName 
                    # Add all the data
                    
                    for kc in relatedTask._kcs:
                        kcSet.add(kc)
                    
                    if relatedTask._assistmentsItem is not None:
                        for assignment in relatedTask._assistmentsItem._assignments:
                            assignmentSet.add(assignment)
                    
                
                collectedTask._kcs = list(kcSet) # This is the complete set accumulated from all subtasks
                collectedAssistmentsItem._assignments = list(assignmentSet)# The assignments inside of this should be the set of all non-duplicate, non-empty ASSISTments assignments from the subtasks
                
                collectedTask._assistmentsItem = collectedAssistmentsItem
                    
                result.append(collectedTask)

        
        logInfo('Exiting CSVReader.processCSVFile', 4)    
        return result
            

Created on Mar 18, 2016
 This module is responsible for converting the tasks csv file to tasks objects and sends them out to the storage service
 @author: auerbach #depending on the content of the message react differently #logInfo('Entering CSVReader.receiveMessage', 5) #Only considering #List of strings #list of tasks # Extract Row Data # Create the Task # logInfo('{0} is constructing the next serializable task object'.format(CSV_READER_SERVICE_NAME), 5) # logInfo('{0} is extracting the knowledge components'.format(CSV_READER_SERVICE_NAME), 5) #if there is an assismentsItem associated with this task #this could cause performance trouble so only use this log if you need to. #logInfo('{0} constructed task: {1}'.format(CSV_READER_SERVICE_NAME, serializeObject(task)), 5) # logInfo('{0} constructed task with name: {1}'.format(CSV_READER_SERVICE_NAME, task._name), 5) #make additional tasks to represent combined tasks #collectedTask._ids.append()#What's going on here? # Subtask ids instead of ids field # Add all the data # This is the complete set accumulated from all subtasks # The assignments inside of this should be the set of all non-duplicate, non-empty ASSISTments assignments from the subtasks