/**
 * Implementation of hook_civicrm_buildAmount()
 *
 * If the event id of the form being loaded has a discount code, calculate the
 * the discount and update the price and label. Apply the initial autodiscount
 * based on a users membership.
 *
 * Check all priceset items and only apply the discount to the discounted items.
 *
 * @param string $pageType
 * @param CRM_Core_Form $form
 * @param $amounts
 */
function cividiscount_civicrm_buildAmount($pagetype, &$form, &$amounts)
{
    if ((!$form->getVar('_action') || $form->getVar('_action') & CRM_Core_Action::PREVIEW || $form->getVar('_action') & CRM_Core_Action::ADD || $form->getVar('_action') & CRM_Core_Action::UPDATE) && !empty($amounts) && is_array($amounts) && ($pagetype == 'event' || $pagetype == 'membership')) {
        if (!$pagetype == 'membership' && in_array(get_class($form), array('CRM_Contribute_Form_Contribution', 'CRM_Contribute_Form_Contribution_Main'))) {
            return;
        }
        // // Don't provide Discount if the logged in user already subscribed to any membership types in the form
        $currentMemberships = $form->_currentMemberships;
        //if logged in
        if (!empty($currentMemberships)) {
            $new_member = FALSE;
        } else {
            // if not logged in
            $new_member = validate_email_for_discount($form);
        }
        /*
        Check if a payment type is set for discounts
        */
        $payids = array();
        $payids = _cividiscount_get_discounted_paymentProcessor_type_ids();
        $selectedProcessorValue = $form->_paymentProcessor['payment_processor_type_id'];
        $contact_id = _cividiscount_get_form_contact_id($form);
        $autodiscount = FALSE;
        $eid = $form->getVar('_eventId');
        $psid = $form->get('priceSetId');
        $ps = $form->get('priceSet');
        $v = $form->getVar('_values');
        $code = trim(CRM_Utils_Request::retrieve('discountcode', 'String', $form, false, null, 'REQUEST'));
        if (!array_key_exists('discountcode', $form->_submitValues) && ($pid = $form->getVar('_participantId')) && $form->getVar('_action') & CRM_Core_Action::UPDATE) {
            $code = _cividiscount_get_item_by_track('civicrm_participant', $pid, $contact_id, TRUE);
        }
        if (!empty($v['currency'])) {
            $currency = $v['currency'];
        } elseif (!empty($v['event']['currency'])) {
            $currency = $v['event']['currency'];
        } else {
            $currency = CRM_Core_Config::singleton()->defaultCurrency;
        }
        // If additional participants are not allowed to receive a discount we need
        // to interrupt the form processing on build and POST.
        // This is a potential landmine if the form processing ever changes in Civi.
        if (!_cividiscount_allow_multiple()) {
            // POST from participant form to confirm page
            if ($form->getVar('_lastParticipant') == 1) {
                return;
            }
            // On build participant form
            $keys = array_keys($_GET);
            foreach ($keys as $key) {
                if (substr($key, 0, 16) == "_qf_Participant_") {
                    // We can somewhat safely assume we're in the additional participant
                    // registration form.
                    // @todo what is the effect of this?
                    if ($_GET[$key] == 'true') {
                        return;
                    }
                }
            }
        }
        if (!$new_member && !empty($code)) {
            echo "Sorry! Discount is not applicable for renewal!";
            return;
        }
        if (!empty($payids) && !empty($code)) {
            if (!in_array($selectedProcessorValue, $payids)) {
                echo "Sorry! Discount is only applicable for Direct Debit!";
                return;
            }
        }
        $form->set('_discountInfo', NULL);
        $dicountCalculater = new CRM_CiviDiscount_DiscountCalculator($pagetype, $eid, $contact_id, $code, FALSE);
        $discounts = $dicountCalculater->getDiscounts();
        if (!empty($code)) {
            if (empty($discounts)) {
                $form->set('discountCodeErrorMsg', ts('The discount code you entered is invalid.'));
            } else {
                /*gets discounts info, even if a discount code is not applicable 
                  for the membership types in the current form */
                // Check if a discount code is applicable to any of the membership types in the form
                $membership_ids_in_form = membership_type_ids_in_form($form);
                $membership_ids_in_dicount_info = array();
                foreach ($discounts as $code => $discount) {
                    $membership_ids_in_dicount_info = $discount['memberships'];
                }
                if (count(array_intersect($membership_ids_in_dicount_info, $membership_ids_in_form)) == 0) {
                    $form->set('discountCodeErrorMsg', ts('The discount code you entered is invalid.'));
                }
            }
        }
        if (empty($discounts)) {
            // Check if a discount is available
            if ($pagetype == 'event') {
                $discounts = _cividiscount_get_discounts();
                foreach ($discounts as $code => $discount) {
                    if (isset($discount['events']) && array_key_exists($eid, $discount['events']) && $discount['discount_msg_enabled']) {
                        // Display discount available message
                        CRM_Core_Session::setStatus(html_entity_decode($discount['discount_msg']), '', 'no-popup');
                    }
                }
            }
            return;
        }
        // here we check if discount is configured for events or for membership types.
        // There are two scenarios:
        // 1. Discount is configure for the event or membership type, in that case we should apply discount only
        //    if default fee / membership type is configured. ( i.e price set with quick config true )
        // 2. Discount is configure at price field level, in this case discount should be applied only for
        //    that particular price set field.
        // here we need to check if selected price set is quick config
        $isQuickConfigPriceSet = CRM_CiviDiscount_Utils::checkForQuickConfigPriceSet($psid);
        $keys = array_keys($discounts);
        $key = array_shift($keys);
        // in this case discount is specified for event id or membership type id, so we need to get info of
        // associated price set fields. For events discount we already have the list, but for memberships we
        // need to filter at membership type level
        //retrieve price set field associated with this priceset
        $priceSetInfo = CRM_CiviDiscount_Utils::getPriceSetsInfo($psid);
        $originalAmounts = $amounts;
        //$discount = array_shift($discounts);
        foreach ($discounts as $done_care => $discount) {
            if (!empty($dicountCalculater->autoDiscounts) && array_key_exists($done_care, $dicountCalculater->autoDiscounts)) {
                $autodiscount = TRUE;
            } else {
                $autodiscount = FALSE;
            }
            $priceFields = isset($discount['pricesets']) ? $discount['pricesets'] : array();
            if (empty($priceFields) && (!empty($code) || $autodiscount)) {
                // apply discount to all the price fields for quickconfig pricesets
                if ($pagetype == 'event' && $isQuickConfigPriceSet) {
                    $applyToAllLineItems = TRUE;
                    if (!empty($key)) {
                        $discounts[$key]['pricesets'] = array_keys($priceSetInfo);
                    }
                } else {
                    // filter only valid membership types that have discount
                    foreach ($priceSetInfo as $pfID => $priceFieldValues) {
                        if (!empty($priceFieldValues['membership_type_id']) && in_array($priceFieldValues['membership_type_id'], CRM_Utils_Array::value('memberships', $discount, array()))) {
                            $priceFields[$pfID] = $pfID;
                        }
                    }
                }
            }
            $apcount = _cividiscount_checkEventDiscountMultipleParticipants($pagetype, $form, $discount);
            if (empty($apcount)) {
                //this was set to return but that doesn't make sense as there might be another discount
                continue;
            }
            $discountApplied = FALSE;
            if (!empty($autodiscount) || !empty($code)) {
                foreach ($amounts as $fee_id => &$fee) {
                    if (!is_array($fee['options'])) {
                        continue;
                    }
                    foreach ($fee['options'] as $option_id => &$option) {
                        if (!empty($applyToAllLineItems) || CRM_Utils_Array::value($option['id'], $priceFields)) {
                            $originalLabel = $originalAmounts[$fee_id]['options'][$option_id]['label'];
                            $originalAmount = CRM_Utils_Rule::cleanMoney($originalAmounts[$fee_id]['options'][$option_id]['amount']);
                            list($amount, $label) = _cividiscount_calc_discount($originalAmount, $originalLabel, $discount, $autodiscount, $currency);
                            $discountAmount = $originalAmounts[$fee_id]['options'][$option_id]['amount'] - $amount;
                            if ($discountAmount > CRM_Utils_Array::value('discount_applied', $option)) {
                                $option['amount'] = $amount;
                                $option['label'] = $label;
                                $option['discount_applied'] = $discountAmount;
                            }
                            $discountApplied = TRUE;
                        }
                    }
                }
            }
        }
        // this seems to incorrectly set to only the last discount but it seems not to matter in the way it is used
        if (isset($discountApplied) && $discountApplied) {
            if (!empty($ps['fields'])) {
                $ps['fields'] = $amounts;
                $form->setVar('_priceSet', $ps);
            }
            $form->set('_discountInfo', array('discount' => $discount, 'autodiscount' => $autodiscount, 'contact_id' => $contact_id));
        }
    }
}