/* global SCE, moment, $ */
SCE.add('sce-ds-calendar-manager', function (Y) {
    'use strict'

    /**
     * [showError description]
     * @param  {[type]} err                      [description]
     * @param  {[type]} stopExceptionPropagation [description]
     * @return {[type]}                          [description]
     */
    function _showError(err, stopExceptionPropagation) {
        Y.SCE.Error.notify(err)
        if (!stopExceptionPropagation) {
            throw err
        }
    }

    Y.namespace('SCE.ds').CalendarManager = {

        /* ********************************************************************* LOAD DATA ******************************************************************** */


        /**
         * [loadActivitiesResourceId description]
         * @param  {[type]} activitiesIds [description]
         * @return {[type]}               [description]
         */
        getDocksByRequestorCodes(requestorCodes, siteCode) {

            return new Promise((resolve, reject) => {

                if (requestorCodes && requestorCodes.length > 0) {
                    var uniqueRequestorCodes = [...new Set(requestorCodes)];
                    var requestorCodeFormatted = '';
                    for (var index = 0; index < uniqueRequestorCodes.length; index++) {
                        requestorCodeFormatted = requestorCodeFormatted + '&requestorCodes=' + uniqueRequestorCodes[index];
                    }
                    requestorCodeFormatted = requestorCodeFormatted + '&siteCode=' + siteCode;

                    let url = Y.SCE.DataSync.API_ORIGIN + `/ds/getDocksByRequestorCodes?` + requestorCodeFormatted;
                    let header = {'Accept': 'application/json'}
                    Y.SCE.DataSync.doIo(Y, url, 'GET', header, null, {}, (error, response) => {
                        error ? reject(error) : resolve(response)
                    });
                } else {
                    resolve();
                }


            })
                .then(requestorDockMapping => {
                    if (requestorDockMapping) {
                        return JSON.parse(requestorDockMapping);
                    } else
                        return {};
                })
                .catch(error => {
                    _showError(error)
                })

        },


        /**
         * Load the list of all the existing resources
         * @param  {[type]} resourceRef [description]
         * @return {[type]}             [description]
         */
        loadResources(resourceRef) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Resource')
            let data = model.createDataModelList()

            let query = {
                'referencedEntity.entityName': resourceRef.name
            }
            if (resourceRef.entityId && resourceRef.entityId.length > 0) {
                query['referencedEntity.entityId'] = resourceRef.entityId
            }
            if (resourceRef.businessKey && resourceRef.businessKey.length > 0) {
                query['referencedEntity.businessKey'] = resourceRef.businessKey
            }
            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    return data.toArray().map(r => {
                        let res = r.toJSON()
                        res.title = res.description ? res.description : res.code
                        return res
                    })
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadRequestors description]
         * @param  {[type]} query [description]
         * @return {[type]}       [description]
         */
        loadRequestors(query) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Requestor')
            let data = model.createDataModelList()

            // Set default query params
            if (!query) {
                query = {
                    _select: 'id, code, description'
                }
            }
            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    return data.toArray().map(r => r.toJSON())
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadDocks description]
         * @param  {[type]} siteCode [description]
         * @return {[type]}          [description]
         */
        loadDocks(siteCode) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Dock')
            let query = {
                _select: 'id, code, description, building.plant.code,building.site.code'
            }
            if (siteCode && siteCode !== '') {
                query['building.site.code'] = siteCode
            } else { // reset any filter
                model.set('filter', null);
            }

            let data = model.createDataModelList()
            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    return data.toArray().map(d => d.toJSON())
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * Load the list of the delivery windows of all the requestors for the actual site
         * @param  {[type]} resourceRef [description]
         * @return {[type]}             [description]
         */
        loadDeliveryWindows(siteCode, requestorsCodes) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Resource')
            let data = model.createDataModelList()

            let query = {
                'referencedEntity.entityName': 'DeliveryWindow',
                'referencedEntity.businessKey': requestorsCodes.map(rc => siteCode.concat(` - ${rc}`))
            }
            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    return data.toArray().map(dl => dl.toJSON())
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadResourceSaturationInfo description]
         * @param  {[type]} from        [description]
         * @param  {[type]} to          [description]
         * @param  {[type]} resourceRef [description]
         * @return {[type]}             [description]
         */
        loadResourceSaturationInfo(from, to, resourceRef) {
            let url = Y.SCE.DataSync.API_ORIGIN + `/ds/resources/saturationInfo`
            let header = {
                'Accept': 'application/json',
                'Content-Type': 'application/x-www-form-urlencoded'
            }

            let param = {
                _from: from,
                _to: to
            }

            for (let key in resourceRef) {
                param[key] = resourceRef[key]
            }

            return new Promise((resolve, reject) => {
                Y.SCE.DataSync.doIo(Y, url, 'POST', header, $.param(param, true), {}, (error, response) => {
                    error ? reject(error) : resolve(response)
                })
            })
                .then(saturationInfo => {
                    return JSON.parse(saturationInfo)
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * Load all the resources and the relative activities between two instants of time
         * @param  {[type]} from        [description]
         * @param  {[type]} to          [description]
         * @param  {[type]} resourceRef [description]
         * @return {[type]}             [description]
         */
        loadResourceAllocationInfo(from, to, siteCode, requestorCode, includeInactivities, resourceRef) {
            let url = Y.SCE.DataSync.API_ORIGIN + `/ds/resources/allocationInfo`
            let header = {
                'Accept': 'application/json',
                'Content-Type': 'application/x-www-form-urlencoded'
            }

            let param = {
                _siteCode: siteCode,
                _requestorCode: requestorCode,
                _from: from,
                _to: to,
                _includeInactivities: includeInactivities
            }

            // NOTE
            // If (rr.businessKeys != empty) for at least one element then Y.SCE.DataSync.doIo will return
            // only the resources with the specified businessKeys. The entityName will become ininfluent.
            // Example:
            //  INPUT ===>
            //     {
            //       referencedEntity.entityName: 'Dock',
            //       referencedEntity.businessKeys = ['D1', 'D2']
            //     },
            //     {
            //       referencedEntity.entityName: 'Requestor'
            //     },
            //     {
            //       referencedEntity.entityName: 'Truck'
            //       referencedEntity.businessKeys = ['T40']
            //     }
            //  ==> OUTPUT: the allocation info of the resources with businessKeys D1, D2 and T40
            resourceRef.forEach(rr => {
                if (!param['referencedEntity.entityName'] || param['referencedEntity.entityName'].length === 0) {
                    param['referencedEntity.entityName'] = [];
                }
                param['referencedEntity.entityName'].push(rr.name)

                if (rr.businessKeys && rr.businessKeys.length > 0) {
                    param['referencedEntity.businessKey'] = rr.businessKeys;
                }
            })

            return new Promise((resolve, reject) => {
                Y.SCE.DataSync.doIo(Y, url, 'POST', header, $.param(param, true), {}, (error, response) => {
                    error ? reject(error) : resolve(response)
                })
            })
                .then(allocationInfo => {
                    return JSON.parse(allocationInfo)
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * Load all the resources and the relative activities between two instants of time
         * TODO: implement filter like in POST.[In the POST request it's possible to send a resource object to add more filters]
         * @param resourceId
         * @param from
         * @param to
         * @return
         */
        loadResourceAllocationInfoGET(from, to, includeInactivities, resourceRefName) {
            let url = Y.SCE.DataSync.API_ORIGIN + `/ds/resources/allocationInfo?_from=${from}&_to=${to}&_resource={referencedEntity.entityName: ${resourceRefName}}`
            let header = {'Accept': 'application/json'}

            return new Promise((resolve, reject) => {
                Y.SCE.DataSync.doIo(Y, url, 'GET', header, null, {}, (error, response) => {
                    error ? reject(error) : resolve(response)
                })
            })
                .then(allocationInfo => {
                    return JSON.parse(allocationInfo)
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadOverlapping description]
         * @param  {[type]} from                [description]
         * @param  {[type]} to                  [description]
         * @param  {[type]} includeInactivities [description]
         * @param  {[type]} resourceRefName     [description]
         * @return {[type]}                     [description]
         */
        loadActivitiesOverlappingMinutesLimit(plantCode) {
            let url = Y.SCE.DataSync.API_ORIGIN + `/ds/activitiesOverlappingMinutesLimit`
            // let header = { 'Accept': 'application/json' }

            let param = {
                _plantCode: plantCode
            }

            return new Promise((resolve, reject) => {
                Y.SCE.DataSync.doIo(Y, url, 'GET', null, $.param(param, true), {}, (error, response) => {
                    error ? reject(error) : resolve(response)
                })
            })
                .then(minutes => {
                    return JSON.parse(minutes)
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadAppointmentsArrivalHourDifference description]
         * @param  {[type]} from          [description]
         * @param  {[type]} to            [description]
         * @param  {[type]} requestorsIds [description]
         * @param  {[type]} siteCode      [description]
         * @return {[type]}               [description]
         */
        loadAppointmentsArrivalHourDifference(from, to, requestorsIds, siteCode) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Appointment')
            let data = model.createDataModelList()

            let query = ({
                _select: `id, arrivalHourDifference, plannedTime`,
                _condition: `plannedTime>= ${from} AND plannedTime<${to}`,
                status: ['IN_PROGRESS', 'COMPLETED'],
                'site.code': `${siteCode}`
            })

            if (requestorsIds && requestorsIds.length > 0) {
                query['requestor.id'] = requestorsIds
            }

            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    // return JSON.parse(data)
                    return data.toArray().map(hr => hr.toJSON())
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * Loads the dates in which there are appointments
         * which are still in status Planning or to plan
         * @param  from starting date
         * @param requestorsIds [Optional] the requestor Ids to consider for the query
         * @param siteCode the code of the site used to filter the query results
         * @return  {Promise<any[]>}  A promise which returns
         * the dates in which there are appointmens in
         * status to plan or planning
         */
        loadActivitiesDates(from, requestorsIds, siteCode) {

            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Appointment');
            let data = model.createDataModelList()
            let query = {
                _select: `validFrom, validTo`,
                _condition: `(status = "PLANNING" OR status = "TO_PLAN") AND (validTo > "${from}")`,
                _orderBy: `validFrom`
            }
            if (siteCode) {
                query['site.code'] = siteCode;
            }

            if (requestorsIds && requestorsIds.length > 0) {
                query['requestor.id'] = requestorsIds
            }

            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    let setOfDates = new Set();
                    data.toArray().map(app => app.toJSON())
                        .forEach(app=>{
                            let currentDate = moment(app.validFrom).startOf('day')
                            //for every date from valid from to valid to I
                            //add to the set of dates in which there are appointments
                            while(currentDate < app.validTo){
                                setOfDates.add(currentDate.valueOf())
                                currentDate=currentDate.add(1,'days');
                            }
                        });
                    return Array.from(setOfDates); //set of dates in which there are appoinments
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * Load appointments for current requestor
         * @param  {[type]} from          [description]
         * @param  {[type]} to            [description]
         * @param  {[type]} requestorsIds [description]
         * @return {[type]}               [description]
         */
        loadActivities(from, to, requestorsIds, role, appointmentConfig, siteCode) {
            let appointmentModel = Y.SCE.ResourcecomponentModel.create('ds', 'Appointment', null, null, appointmentConfig)
            let data = appointmentModel.createDataModelList()
            let self = this
            let activityModel = Y.SCE.ResourcecomponentModel.create('ds', 'Activity')

            let query = {
                _include: `id, code, recurrentAppointment.id, description,supplier,requestor, externalId, requestor.id, requestor.code, expectedTime, predictedTime, elapsedFrom, elapsedTo, elapsedGateFrom, truckInfo.truckType, status, site,activityRequests,activityRequests.plant,activityRequests.content,activityRequests.content.itemType,activityRequests.content.supplier`,
                _condition: `status <> "CANCELLED" AND status <> "EXPIRED" AND ((elapsedFrom > "${from}" AND elapsedTo < "${to}") or (validTo >= "${from}" AND validFrom <= "${to}"))`,
                _orderBy: `code`
            }
            // OR EXISTS activities[upperBoundTo > "${from}" AND lowerBoundFrom < "${to}"]
            if (requestorsIds && requestorsIds.length > 0) {
                query['requestor.id'] = requestorsIds
            }
            if (siteCode) {
                query['site.code'] = siteCode;
            }

            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    let finalArr = [];

                    let appointmentList = data.toArray().map(a => a.toJSON());
                    let appointMapById = {};
                    appointmentList.forEach(a => {
                        appointMapById[a.id] = a;
                    });

                    return self.loadAppointmentActivities(appointmentList, appointmentModel, from, to, activityModel, role)
                        .then(resList => {
                            resList = JSON.parse(resList);

                            resList.forEach(res => {
                                let appointment = appointMapById[res.appointment.entityId]

                                if (res.activityList) {
                                    let partialResult = self.postLoadAppointmentActivities(appointment, appointmentModel, from, to, activityModel, role, res.activityList, res.activityIdToResources)
                                    finalArr = finalArr.concat(partialResult);
                                }
                            });
                            return finalArr;
                        })
                        .catch(error => {
                            _showError(error)
                        })
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadPerAppointmentActivities description]
         * @param  {[type]} appointmentList     [description]
         * @param  {[type]} appointmentModel [description]
         * @param  {[type]} from             [description]
         * @param  {[type]} to               [description]
         * @param  {[type]} activityModel    [description]
         * @param  {[type]} role             [description]
         * @return {[type]}                  [description]
         */
        loadAppointmentActivities(appointmentList, appointmentModel, from, to, activityModel, role) {
            let linkViewName = role === 'manager' ? 'AppointmentManagerView' : 'AppointmentRequestorView'
            let attributeModel = {
                get: () => {
                    return 'ds/' + linkViewName + '?code=' + currentValue.code
                }
            }

            // Take each activityRequest and get the corresponding activities
            let url = Y.SCE.DataSync.API_ORIGIN + `/ds/resources/activities`
            let header = {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            }

            let body = Y.JSON.stringify({
                appointmentList: appointmentList.map(a => a.id),
                from,
                to
            })

            return new Promise((resolve, reject) => {
                Y.SCE.DataSync.doIo(Y, url, 'POST', header, body, {}, (error, response) => {
                    error ? reject(error) : resolve(response)
                })
            })
        },

        postLoadAppointmentActivities(currentValue, appointmentModel, from, to, activityModel, role, activitiesData, resourcesUsage) {
            let linkViewName = role === 'manager' ? 'AppointmentManagerView' : 'AppointmentRequestorView'
            let attributeModel = {
                get: () => {
                    return 'ds/' + linkViewName + '?code=' + currentValue.code
                }
            }
            let appointmentLink = Y.SCE.Picker.Link.getPickerAsHtml(currentValue, attributeModel, appointmentModel, Y.SCE.Picker.Factory)

            let activities = activitiesData
            return activities.map(activity => {
                let skuQuantity = this.getSkusQuantity(currentValue, activity);
                let myRegexpAppLink = /(<a.+>)(.*)(<\/a>)/g
                let matchAppLink = myRegexpAppLink.exec(appointmentLink)
                let myRegexpAppLink2 = /(.*data-content=\")(.*)/g
                let matchAppLink2 = myRegexpAppLink2.exec(matchAppLink[1])
                let intermediateContent = matchAppLink2[1].concat("<div><label data-sce-intl=ds:resources/Appointment:durata>Durata</label><span>").concat(this.getDuration(activity))
                    .concat("</span></div><div><label data-sce-intl=ds:resources/Appointment:colli>Colli</label><span>").concat(skuQuantity).concat("</span></div>");
                let itemTypeDescription = undefined;
                let itemTypeHTMLTag = undefined;

                //In DS system each item type will be show as one different block
                //In this case we are sure to assign the description based on [0] element.
                if (activity.relatedEntities && activity.relatedEntities.length > 0) {
                    let contentDescription = activity.relatedEntities[0].businessKey;
                    if (contentDescription) {
                        itemTypeDescription = contentDescription;
                        itemTypeHTMLTag = "<div><label data-sce-intl=ds:resources/Appointment:articolo>Articolo</label><span>".concat(itemTypeDescription).concat("</span></div>");
                    }


                }
                if (itemTypeDescription) {
                    intermediateContent = intermediateContent.concat(itemTypeHTMLTag);
                }
                matchAppLink[1] = intermediateContent.concat(matchAppLink2[2]);

                let appointmentLinkWithActivityScreenLabel = matchAppLink[1].concat(this.getLabel(currentValue, activity)).concat(skuQuantity).concat(matchAppLink[3])


                return ({
                    plannedTime: moment(activity.elapsedFromDateTime),
                    resourcesUsage: resourcesUsage,
                    id: activity.id,
                    title: appointmentLinkWithActivityScreenLabel,
                    timeSlotAllocationStatus: activity.timeSlotAllocationStatus,
                    resourcesAllocationStatus: activity.resourcesAllocationStatus,
                    duration: moment.duration(activity.totalEffortSec, 'seconds'),
                    // The query doesn't retrieve the lazy collections of Activity.
                    // resourceId: (activity.resourceUsages ? activity.resourceUsages[0].resource.id : null),
                    // start: (activity.timeSlots ? moment(activity.timeSlots[0].from) : moment()),
                    // end: (activity.timeSlots ? moment(activity.timeSlots[0].to) : null),
                    resourceId: null,
                    start: moment(), // The start field is mandatory for the creation of an event
                    end: null,
                    activityType: activity.activityType,
                    itemTypeIds: activity.relatedEntities && activity.relatedEntities.filter(re => re.entityName === 'ItemType').length > 0 ? activity.relatedEntities.filter(re => re.entityName === 'ItemType') : null, // Array of entitites
                    truckTypeId: currentValue.truckInfo && currentValue.truckInfo.truckType ? parseInt(currentValue.truckInfo.truckType.id) : null,
                    constraint: {
                        start: activity.lowerBoundFromDateTime,
                        end: activity.upperBoundToDateTime
                    },
                    lowerBoundNow: activity.lowerBoundNow,
                    maxTimeToModify: activity.maxTimeToModify,
                    resourceRef: currentValue.description,
                    referencedEntityId: activity.referencedEntity.entityId,
                    screenLabel: currentValue.requestor.code,
                    className: ['requestor-activities'],
                    durationEditable: false,
                    overlap: true,
                    appointmentReference: {
                        id: currentValue.id,
                        code: currentValue.code,
                        status: currentValue.status,
                        referenceRequest: currentValue.activityRequests.filter(r => r.id == activity.referencedEntity.entityId)[0],
                        requestorId: currentValue.requestor.id,
                        requestor: currentValue.requestor,
                        supplier: currentValue.supplier,
                        site: currentValue.site,
                        activityRequests: currentValue.activityRequests,
                        requestorCode: currentValue.requestor.code,
                        appointmentLink: appointmentLink,
                        recurrentAppointment: currentValue.recurrentAppointment ? true : false
                    },
                    toReschedule: activity.toReschedule,
                    lastOperationDate: activity.lastOperationDate,
                    appointmentLinkWithActivityScreenLabel: appointmentLinkWithActivityScreenLabel
                })
            })
        },

        getDuration(activity) {
            return moment(moment.duration(activity.totalEffortSec, 'seconds').hours(), 'H').format('H')
                + ":"
                + moment(moment.duration(activity.totalEffortSec, 'seconds').minutes(), 'mm').format('mm');
        },

        getLabel(appointment, activity) {
            return this.getActivityLabel(appointment, activity);
        },

        getActivityLabel(appointment, activity) {
            return appointment.code.concat("-" + activity.activityType.type);
        },

        getSkusQuantity(appointment, activity) {
            let qtyLabel = "";
            let quantity = 0;
            let contents = appointment.activityRequests.filter(r => "" + r.id + "" === activity.referencedEntity.businessKey).reduce((a, r) => a.concat(r.content), []);
            if (contents[0] != undefined) {
                contents = contents.filter(c => activity.relatedEntities.filter(e => e.entityName == "ItemType" && e.entityId == c.itemType.id).length > 0)
                quantity = contents.reduce((a, r) => a.concat(r.quantity), []).reduce((sum, rr) => {
                    return sum + rr
                }, 0);
            }
            if (quantity > 0) {
                return qtyLabel.concat(" (").concat(quantity).concat(") ");
            } else
                return qtyLabel;
        },

        /**
         * [loadActivitiesResourceId description]
         * @param  {[type]} activitiesIds [description]
         * @return {[type]}               [description]
         */
        loadActivitiesResourceId(activitiesIds) {
            //This request is performed to get all the resources
            //based on the activity that are not placed inside calendar.
            //this call must be not executed in case activitiesIds is not valorized!
            if (activitiesIds && activitiesIds.length > 0) {
                let model = Y.SCE.ResourcecomponentModel.create('ds', 'ResourceUsage')
                let data = model.createDataModelList()

                data.setQuery({
                    _select: `activity.id, resource.id`,
                    'activity.id': activitiesIds
                })

                return new Promise((resolve, reject) => {
                    data.load(null, (error, response) => {
                        error ? reject(error) : resolve()
                    })
                })
                    .then(() => {
                        return data.toArray().map(r => r.toJSON())
                    })
                    .catch(error => {
                        _showError(error)
                    })
            } else {
                //If here means that we have not unplaced activity inside calendar
                //we can return empty array.
                return [];
            }
        },

        /**
         * [loadItemTypeMatch description]
         * @param  {[type]} dockIds [description]
         * @return {[type]}         [description]
         */
        loadItemTypeMatch(dockIds) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'DockItemType')
            let data = model.createDataModelList()

            data.setQuery({
                _select: `dock.id, itemType.id`,
                'dock.id': dockIds
            })

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    let itemsTypesMatch = {}
                    data.toArray().map(m => m.toJSON()).forEach(m => {
                        if (!itemsTypesMatch[m.dock.id]) {
                            itemsTypesMatch[m.dock.id] = []
                        }
                        itemsTypesMatch[m.dock.id].push(m.itemType.id)
                    })
                    return itemsTypesMatch
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * This function laods the match between activity type and docks
         * @param  {[type]} dockIds id of docks
         * @return {[type]}         The mapping between dock and activity type allowed
         */
        loadActivityTypeMatch(dockIds) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'DockActivityTypeRule')
            let data = model.createDataModelList()

            data.setQuery({
                _select: `dock.id, activityTypeRef.entityId`,
                'dock.id': dockIds
            })

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    let activityTypesMatch = {}
                    data.toArray().map(m => m.toJSON()).forEach(m => {
                        if (!activityTypesMatch[m.dock.id]) {
                            activityTypesMatch[m.dock.id] = []
                        }
                        activityTypesMatch[m.dock.id].push(parseInt(m.activityTypeRef.entityId))
                    })
                    return activityTypesMatch
                })
                .catch(error => {
                    _showError(error)
                })
        },


        /**
         * [loadTruckTypeMatch description]
         * @param  {[type]} dockIds [description]
         * @return {[type]}         [description]
         */
        loadTruckTypeMatch(dockIds) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'DockTruckType')
            let data = model.createDataModelList()

            data.setQuery({
                _select: `dock.id, truckType.id`,
                'dock.id': dockIds
            })

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    let trucksTypesMatch = {}
                    data.toArray().map(m => m.toJSON()).forEach(m => {
                        if (!trucksTypesMatch[m.dock.id]) {
                            trucksTypesMatch[m.dock.id] = []
                        }
                        trucksTypesMatch[m.dock.id].push(m.truckType.id)
                    })
                    return trucksTypesMatch
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadResourcesForPickers description]
         * @return {[type]} [description]
         */
        loadResourcesForPickers(refNames) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Resource')
            let data = model.createDataModelList()

            data.setQuery({
                _select: `description, referencedEntity.entityId, referencedEntity.businessKey, referencedEntity.entityName`,
                'referencedEntity.entityName': refNames
            })

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    return data.toArray().map(r => r.toJSON()).map(r => ({
                        entityId: r.referencedEntity.entityId,
                        businessKey: r.referencedEntity.businessKey,
                        entityName: r.referencedEntity.entityName,
                        description: r.description
                    }))
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * [loadAppointmentConfiguration description]
         * @return {[type]} [description]
         */
        loadAppointmentConfiguration() {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'AppointmentConfiguration')
            let data = model.createDataModelList()

            let query = {}

            data.setQuery(query)

            return new Promise((resolve, reject) => {
                data.load(null, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .then(() => {
                    return data.toArray().map(d => d.toJSON())
                })
                .catch(error => {
                    _showError(error)
                })
        },

        /* ********************************************************************* ACTIVITY ACTION ******************************************************************** */

        /**
         * Call the action to create a time time slots and a resource usage for the selected activity
         * @param  {[type]} activityId    [description]
         * @param  {[type]} from          [description]
         * @param  {[type]} to            [description]
         * @param  {[type]} resourceId    [description]
         * @param  {[type]} operationDate [description]
         * @param  {[type]} validate      [description]
         * @return {[type]}               [description]
         */
        bindTimeSlotToActivity(activityId, from, to, resourceId, operationDate, validate) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Activity')
            let data = model.createDataModel({id: activityId})

            return new Promise((resolve, reject) => {
                data.action({
                    actionDataModel: new Y.SCE.DataModel({
                        from: from,
                        to: to,
                        resource: {id: resourceId},
                        operationDate: operationDate
                    }),
                    actionName: 'associateTimeSlot'
                }, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .catch(error => {
                    _showError(error)
                })
        },

        /**
         * Replace the timeslot previously occupied with the new one.
         * the drag temporal distance from the dropped time slot.
         * @param  {[type]} activityId    [description]
         * @param  {[type]} targetFrom    represents the new time slot start date
         * @param  {[type]} targetTo      represents the new time slot end date
         * @param  {[type]} sourceFrom    represent the old time slot start date. This is the date of the slot that has been moved to a new one.
         * @param  {[type]} resourceId    [description]
         * @param  {[type]} operationDate [description]
         * @param  {[type]} validate      [description]
         * @return {[type]}               [description]
         */
        changeTimeSlotToActivity(activityId, targetFrom, targetTo, sourceFrom, resourceId, operationDate, validate) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Activity')
            let data = model.createDataModel({id: activityId})

            return new Promise((resolve, reject) => {
                data.action({
                    actionDataModel: new Y.SCE.DataModel({
                        from: targetFrom,
                        to: targetTo,
                        oldFrom: sourceFrom,
                        resource: {id: resourceId},
                        operationDate: operationDate
                    }),
                    actionName: validate ? 'changeTimeSlot' : 'forceChangeTimeSlot'
                }, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .catch(err => {
                    _showError(err)
                })
        },

        /**
         * Call the action to delete time slots and resource usage related to the selected activitty
         * @param  {[type]} activityId    [description]
         * @param  {[type]} resourceId    [description]
         * @param  {[type]} operationDate [description]
         * @param  {[type]} validate      [description]
         * @return {[type]}               [description]
         */
        unbindTimeSlotToActivity(activityId, resourceId, operationDate, validate) {
            let model = Y.SCE.ResourcecomponentModel.create('ds', 'Activity')
            let data = model.createDataModel({id: activityId})

            return new Promise((resolve, reject) => {
                data.action({
                    actionDataModel: new Y.SCE.DataModel({resource: {id: resourceId}, operationDate: operationDate}),
                    actionName: validate ? 'disassociateTimeSlot' : 'forceDisassociateTimeSlot'
                }, (error, response) => {
                    error ? reject(error) : resolve()
                })
            })
                .catch(error => {
                    _showError(error)
                })
        }
    }
}, '0.0.1', {
    requires: []
})


Can you add moment timezone handling here?