/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
*/
package org.apache.ofbiz.product.facility.shipment

import org.apache.ofbiz.entity.condition.EntityCondition

shipmentId = request.getParameter('shipmentId') ?: context.shipmentId
orderId = request.getParameter('orderId')
shipGroupSeqId = request.getParameter('shipGroupSeqId')

action = request.getParameter('action')

shipment = null
if (shipmentId) {
    shipment = from('Shipment').where('shipmentId', shipmentId).queryOne()
}

// **************************************
// Order Items are searched also by shipGroupSeqId and put in orderItemShipGroupAssocs
// **************************************
orderItemShipGroupAssocs = null
// **************************************
// Search method: search by productId
// **************************************
if (action && orderId) {
    if (shipGroupSeqId) {
        orderItemShipGroupAssocs = from('OrderItemShipGroupAssoc').where('orderId', orderId, 'shipGroupSeqId', shipGroupSeqId).queryList()
    } else {
        orderItemShipGroupAssocs = from('OrderItemShipGroupAssoc').where('orderId', orderId).queryList()
    }
}

// **************************************
// ShipmentPlan list form
// **************************************
totWeight = 0
totVolume = 0
shipmentPlans = null
shipmentPlansIt = null
rows = [] as ArrayList
if (shipment) {
    shipmentPlans = from('OrderShipment').where('shipmentId', shipment.shipmentId).queryList()
}
if (shipmentPlans) {
    shipmentPlans.each { shipmentPlan ->
        oneRow = new HashMap(shipmentPlan)
        orderItem = shipmentPlan.getRelatedOne('OrderItem', false)
        oneRow.productId = orderItem.productId
        orderedQuantity = orderItem.getDouble('quantity')
        canceledQuantity = orderItem.getDouble('cancelQuantity')
        if (canceledQuantity) {
            orderedQuantity = Double.valueOf(orderedQuantity.doubleValue() - canceledQuantity.doubleValue())
        }
        oneRow.totOrderedQuantity = orderedQuantity.intValue()

        // Total quantity issued
        issuedQuantity = 0.0
        qtyIssuedInShipment = [:]
        issuances = orderItem.getRelated('ItemIssuance', null, null, false)
        issuances.each { issuance ->
            if (issuance.quantity) {
                issuedQuantity += issuance.getDouble('quantity')
                if (issuance.cancelQuantity) {
                    issuedQuantity -= issuance.getDouble('cancelQuantity')
                }
                if (qtyIssuedInShipment.containsKey(issuance.shipmentId)) {
                    qtyInShipment = ((Double)qtyIssuedInShipment.get(issuance.shipmentId)).doubleValue()
                    qtyInShipment += issuance.getDouble('quantity')
                    if (issuance.cancelQuantity) {
                        qtyInShipment -= issuance.getDouble('cancelQuantity')
                    }
                    qtyIssuedInShipment.put(issuance.shipmentId, qtyInShipment)
                } else {
                    qtyInShipment = issuance.getDouble('quantity')
                    if (issuance.cancelQuantity) {
                        qtyInShipment -= issuance.getDouble('cancelQuantity')
                    }
                    qtyIssuedInShipment.put(issuance.shipmentId, qtyInShipment)
                }
            }
        }
        oneRow.totIssuedQuantity = issuedQuantity
        // Total quantity planned not issued
        plannedQuantity = 0.0
        qtyPlannedInShipment = [:]
        plans = from('OrderShipment').where('orderId', orderItem.orderId, 'orderItemSeqId', orderItem.orderItemSeqId).queryList()
        plans.each { plan ->
            if (plan.quantity) {
                netPlanQty = plan.getDouble('quantity')
                if (qtyIssuedInShipment.containsKey(plan.shipmentId)) {
                    qtyInShipment = ((Double)qtyIssuedInShipment.get(plan.shipmentId)).doubleValue()
                    if (netPlanQty > qtyInShipment) {
                        netPlanQty -= qtyInShipment
                    } else {
                        netPlanQty = 0
                    }
                }
                plannedQuantity += netPlanQty
                if (qtyPlannedInShipment.containsKey(plan.shipmentId)) {
                    qtyInShipment = ((Double)qtyPlannedInShipment.get(plan.shipmentId)).doubleValue()
                    qtyInShipment += netPlanQty
                    qtyPlannedInShipment.put(plan.shipmentId, qtyInShipment)
                } else {
                    qtyPlannedInShipment.put(plan.shipmentId, netPlanQty)
                }
            }
        }
        oneRow.totPlannedQuantity = plannedQuantity
        if (qtyIssuedInShipment.containsKey(shipmentId)) {
            oneRow.issuedQuantity = qtyIssuedInShipment.get(shipmentId)
        } else {
            oneRow.issuedQuantity = ''
        }
        // Reserved and Not Available quantity
        reservedQuantity = 0.0
        reservedNotAvailable = 0.0
        reservations = orderItem.getRelated('OrderItemShipGrpInvRes', null, null, false)
        reservations.each { reservation ->
            if (reservation.quantity) {
                reservedQuantity += reservation.getDouble('quantity')
            }
            if (reservation.quantityNotAvailable) {
                reservedNotAvailable += reservation.getDouble('quantityNotAvailable')
            }
        }
        oneRow.notAvailableQuantity = reservedNotAvailable

        // Planned Weight and Volume
        product = orderItem.getRelatedOne('Product', false)
        weight = 0.0
        quantity = 0.0
        if (shipmentPlan.getDouble('quantity')) {
            quantity = shipmentPlan.getDouble('quantity')
        }
        if (product.getDouble('productWeight')) {
            weight = product.getDouble('productWeight') * quantity
        }
        oneRow.weight = weight
        if (product.weightUomId) {
            weightUom = from('Uom').where('uomId', product.weightUomId).queryOne()
            oneRow.weightUom = weightUom.abbreviation
        }
        volume = 0.0
        if (product.getDouble('productHeight') &&
            product.getDouble('productWidth') &&
            product.getDouble('productDepth')) {
            // TODO: check if uom conversion is needed
            volume = product.getDouble('productHeight') *
                product.getDouble('productWidth') *
                product.getDouble('productDepth') *
                quantity
        }
        oneRow.volume = volume
        if (product.heightUomId && product.widthUomId && product.depthUomId) {
            heightUom = from('Uom').where('uomId', product.heightUomId).cache(true).queryOne()
            widthUom = from('Uom').where('uomId', product.widthUomId).cache(true).queryOne()
            depthUom = from('Uom').where('uomId', product.depthUomId).cache(true).queryOne()
            oneRow.volumeUom = heightUom.abbreviation + 'x' + widthUom.abbreviation + 'x' + depthUom.abbreviation
        }
        totWeight += weight
        totVolume += volume
        rows.add(oneRow)
    }
}

// **************************************
// ShipmentPlan add form
// **************************************
addRows = [] as ArrayList
if (orderItemShipGroupAssocs) {
    orderItemShipGroupAssocs.each { orderItemShipGroupAssoc ->
        orderItem = orderItemShipGroupAssoc.getRelatedOne('OrderItem', false)
        oneRow = [:]
        oneRow.shipmentId = shipmentId
        oneRow.orderId = orderItemShipGroupAssoc.orderId
        oneRow.orderItemSeqId = orderItemShipGroupAssoc.orderItemSeqId
        oneRow.shipGroupSeqId = orderItemShipGroupAssoc.shipGroupSeqId
        oneRow.productId = orderItem.productId
        orderedQuantity = orderItemShipGroupAssoc.getDouble('quantity')
        canceledQuantity = orderItemShipGroupAssoc.getDouble('cancelQuantity')
        if (canceledQuantity) {
            orderedQuantity = Double.valueOf(orderedQuantity.doubleValue() - canceledQuantity.doubleValue())
        }
        oneRow.orderedQuantity = orderedQuantity
        // Total quantity issued
        issuedQuantity = 0.0
        qtyIssuedInShipment = [:]
        issuances = orderItem.getRelated('ItemIssuance', null, null, false)
        issuances.each { issuance ->
            if (issuance.quantity) {
                issuedQuantity += issuance.getDouble('quantity')
                if (issuance.cancelQuantity) {
                    issuedQuantity -= issuance.getDouble('cancelQuantity')
                }
                if (qtyIssuedInShipment.containsKey(issuance.shipmentId)) {
                    qtyInShipment = ((Double)qtyIssuedInShipment.get(issuance.shipmentId)).doubleValue()
                    qtyInShipment += issuance.getDouble('quantity')
                    qtyIssuedInShipment.put(issuance.shipmentId, qtyInShipment)
                } else {
                    qtyInShipment = issuance.getDouble('quantity')
                    if (issuance.cancelQuantity) {
                        qtyInShipment -= issuance.getDouble('cancelQuantity')
                    }
                    qtyIssuedInShipment.put(issuance.shipmentId, qtyInShipment)
                }
            }
        }
        oneRow.issuedQuantity = issuedQuantity
        // Total quantity planned not issued
        plannedQuantity = 0.0
        EntityCondition orderShipmentCondition = null
        if (shipGroupSeqId) {
            orderShipmentCondition = EntityCondition.makeCondition(
                    [orderId: orderItemShipGroupAssoc.orderId,
                     orderItemSeqId: orderItemShipGroupAssoc.orderItemSeqId,
                     shipGroupSeqId: orderItemShipGroupAssoc.shipGroupSeqId])
        } else {
            orderShipmentCondition = EntityCondition.makeCondition(
                    [orderId: orderItemShipGroupAssoc.orderId,
                     orderItemSeqId: orderItemShipGroupAssoc.orderItemSeqId])
        }
        plans = from('OrderShipment').where(orderShipmentCondition).queryList()
        plans.each { plan ->
            if (plan.quantity) {
                netPlanQty = plan.getDouble('quantity')
                plannedQuantity += netPlanQty
            }
        }
        oneRow.plannedQuantity = plannedQuantity

        // (default) quantity for plan
        planQuantity = (orderedQuantity - plannedQuantity - issuedQuantity > 0 ? orderedQuantity - plannedQuantity - issuedQuantity : 0)
        oneRow.quantity = planQuantity

        // Planned (unitary) Weight and Volume
        weight = new Double(0)
        product = orderItem.getRelatedOne('Product', false)
        if (product.getDouble('productWeight')) {
            weight = product.getDouble('productWeight')
        }
        oneRow.weight = weight

        if (product.weightUomId) {
            weightUom = from('Uom').where('uomId', product.weightUomId).cache(true).queryOne()
            oneRow.weightUom = weightUom.abbreviation
        }
        volume = 0.0
        if (product.getDouble('productHeight') && product.getDouble('productWidth') && product.getDouble('productDepth')) {
            // TODO: check if uom conversion is needed
            volume = product.getDouble('productHeight') *
                         product.getDouble('productWidth') *
                         product.getDouble('productDepth')
        }

        oneRow.volume = volume
        if (product.heightUomId && product.widthUomId && product.depthUomId) {
            heightUom = from('Uom').where('uomId', product.heightUomId).cache(true).queryOne()
            widthUom = from('Uom').where('uomId', product.widthUomId).cache(true).queryOne()
            depthUom = from('Uom').where('uomId', product.depthUomId).cache(true).queryOne()
            oneRow.volumeUom = heightUom.abbreviation + 'x' + widthUom.abbreviation + 'x' + depthUom.abbreviation
        }
        addRows.add(oneRow)
    }
}

context.listShipmentPlanRows = rows
context.addToShipmentPlanRows = addRows
context.rowCount = addRows.size()
context.shipmentId = shipmentId
context.shipment = shipment
context.totWeight = totWeight
context.totVolume = totVolume
