<?php

class ConfirmationAction extends CartAction {
	
	const OPERATION_EDIT_ORDER = 'edit-order';
	
	public function execute($request) {
		
		$this->form = ResourceLocator::getInstance()->billingAccountService->getCreateAccountForm($this->_store->getId());
		
		if ($request->isMethod('post')) {
			
			$operation = $request->getParameter('operation');
			
			switch ($operation) {
				case self::OPERATION_EDIT_ORDER:
					$router = new Router();
					$router->init(
						array(
							new RouterPage('summary'),
							new RouterPage('order-details'),
							new RouterPage('confirmation')
						),
						new RouterPage('confirmation')
					);
					ResourceLocator::getInstance()->routersStack->push($router);
					$router->next();
					break;
				default:
					
					$this->form->bind($request->getParameter($this->form->getName()));
					
					try {
						
						if (!$this->form->isValid()) {
							throw new BillingFormException('TRANS_STORE_INVALID_ACCOUNT_DATA');
						}

						$accountData = $this->form->save();

						if ($customerData = sfContext::getInstance()->getUser()->getAttribute('customerData')) {
							$inputParams = array_merge($accountData, $customerData);
						} else {
							$inputParams = $accountData;
						}
						$inputParams['client_ip'] = $_SERVER['REMOTE_ADDR'];

						$shoppingSessionData = array();
						$shoppingSessionData['invoiceID'] = 0;
						$shoppingSessionData['shoppingItems'] = array();

						$certificateAddonsRelations = array();

						foreach (ResourceLocator::getInstance()->cart->getPurchases() as $purchase) {
							$plan = $this->_store->getPlan($purchase->getPlanId());
							$price = $plan->getPriceById($purchase->getPriceId());

							$data = false;
							switch ($plan->productType) {
								case BillingPlan::TYPE_DOMAIN:
									$data = $this->prepareDomainData($purchase, $this->_store, $plan, $price, $inputParams);
									break;
								default:
									$data = $this->prepareData($purchase, $this->_store, $plan, $price);
							}
							if ($data) {
								$shoppingSessionData['shoppingItems'][] = $data;
							}

							foreach ($purchase->getCertificateAddons() as $addon) {
								if (!isset($certificateAddonsRelations[$purchase->getId()])) {
									$certificateAddonsRelations[$purchase->getId()] = array();
								}
								$certificateAddonsRelations[$purchase->getId()] = $addon;
							}
						}
						foreach ($certificateAddonsRelations as $shoppingItemId => $addon) {
							$plan = $this->_store->getPlan($addon->getPlanId());
							$billingAddons = $plan->getAddons($this->_store->getId(), $addon->getCycleId());
							if (!$billingAddon = isset($billingAddons[$addon->getAddonId()]) ? $billingAddons[$addon->getAddonId()] : null) {
								continue;
							}
							$data = $this->prepareItemData($addon, $billingAddon->getPrice(), BillingPlan::TYPE_SSL_CERTIFICATE, $shoppingItemId);
							$data['certificates'] = array($this->prepareCertificateData($addon));
							$shoppingSessionData['shoppingItems'][] = $data;
						}

						if ($customer = sfContext::getInstance()->getUser()->getAttribute('customer', null)) {
							$clientId = $customer->clientID;
						} else {
							$clientId = null;
						}

						$tryBeforeBuySiteBuilderParameters = $this->_cart->getParameter('tryBeforeBuySiteBuilderParameters', array());
						$checkoutData = ResourceLocator::getInstance()->billingCheckoutService->executeCheckout(
							$this->_store->getId(),
							$shoppingSessionData,
							$inputParams,
							$clientId,
							$tryBeforeBuySiteBuilderParameters
						);
						if (isset($tryBeforeBuySiteBuilderParameters['sbOneTimeBackUrl'])) {
							$checkoutData['backUrl'] = $tryBeforeBuySiteBuilderParameters['sbOneTimeBackUrl'];
						}
						$this->getUser()->setAttribute('checkoutData', $checkoutData);
						$this->_cart->clean();

						if ($customerData) {
							try {
								ResourceLocator::getInstance()->billingContactService->login($customerData['contactUsername'], $customerData['contactPassword']);
								$this->getUser()->getAttributeHolder()->remove('customerData');
							} catch (StoreException $exception) {
								$this->logMessage('Unable to login as just created customer [login=' . $customerData['contactUsername'] . ']; ' . get_class($exception) . ' message: ' . $exception->getMessage(), 'err');
							}
						}

						$this->_router->next();
								

						
					} catch (BillingFormException $exception) {
						$this->errorMessage = $exception->getMessage();
					}
			}
			
		}
			
		$this->customer = sfContext::getInstance()->getUser()->getAttribute('customer', null);
		$this->customerData = sfContext::getInstance()->getUser()->getAttribute('customerData', null);
		
		sfContext::getInstance()->getConfiguration()->loadHelpers('I18N');
		
		$amount = 0;
		$totalAmount = 0;
		$minimalCycle = null;
		
		$cartItemsData = array();
		foreach (ResourceLocator::getInstance()->cart->getItems() as $cartItemId => $cartItem) {
			$cartItemsData[$cartItemId] = array();
			
			foreach ($cartItem->getPurchases() as $purchase) {
				$subPurchases = $purchase->getPurchases(true);
				$cartItemsData[$cartItemId][$purchase->getId()] = $this->preparePurchaseViewData($purchase, $subPurchases, $amount, $totalAmount, $minimalCycle);
				$addons = array();
				foreach ($purchase->getAddons(true) as $addon) {
					$addons[] = $this->prepareAddonViewData($addon, $amount, $totalAmount, $minimalCycle);
				}
				$cartItemsData[$cartItemId][$purchase->getId()]['addons'] = $addons;
			}
			
		}
		
		$this->amount = $amount;
		$this->totalAmount = $totalAmount;
		$this->minimalCycle = $minimalCycle;
		
		$this->cartItemsData = $cartItemsData;
		
		$this->currencyId = $this->_store->currencyID;
		
		try {
			$this->company = ResourceLocator::getInstance()->billingCompanyService->getProviderCompany();
		} catch (StoreException $exception) {
			$this->logMessage('Unable to get provider company; ' . get_class($exception) . ' message: ' . $exception->getMessage(), 'err');
		}
		
		if ($this->_store->useTermsUrl) {
			$this->externalTermsLink = $this->_store->termsUrl;
		} else {
			$this->internalTermsLink = isset($this->_store->termsText) && $this->_store->termsText ? true : false;
		}
		
	}
	
	private function preparePurchaseViewData($purchase, $subPurchases = array(), &$amount, &$totalAmount, &$minimalCycle) {
		$subData = array();
		
		$plan = ResourceLocator::getInstance()->billingPlanService->getById(
			$purchase->getPlanId(),
			$this->_store->getId(),
			$purchase->hasCoupon() ? $purchase->getCoupon()->getId() : false
		);
		
		if ($plan->productType != BillingPlan::TYPE_DOMAIN && $purchase->hasParameter('domainData')) {
			$fakeId = ResourceLocator::getInstance()->cart->generateFakeId();
			$domainData = $purchase->getParameter('domainData');
			$subData[$fakeId] = array(
				'id' => $fakeId,
				'type' => __('TRANS_YOUR_OWN_DOMAIN'),
				'name' => $domainData['name'],
				'price' => null,
				'cycle' => null,
				'hasAvailableAddons' => false,
				'hasAddDomainAbility' => false,
				'fake' => true,
				'purchases' => array()
			);
		}
		
		foreach ($subPurchases as $subPurchase) {
			$subData[$subPurchase->getId()] = $this->preparePurchaseViewData($subPurchase, array(), $amount, $totalAmount, $minimalCycle);
		}
		
		$useTransferFee = $plan instanceof BillingDomainPlan && $purchase->getParameter('type') == BillingDomainPlan::PURCHASE_TYPE_TRANSFER ? true : false;
		
		$price = $plan->getPriceById($purchase->getPriceId());
		$cycle = $plan->getCycle($price->cycleID);
		if (!$minimalCycle || $minimalCycle->getLength() < $cycle->getLength()) {
			$minimalCycle = $cycle;
		}
		$amount += $price->getTotalFee(true, false, $useTransferFee);
		$totalAmount += $price->getTotalFee(true, true, $useTransferFee);
		
		$hasAddAddonAbility = $plan->mayHaveAddons() && $plan->hasAddAddonAvailability($cycle->cycleID);
		
		$hasAddDomainAbility = false;
		if ($plan->mayHaveDomains()) {
			$domainPlan = $plan instanceof BillingDomainPlan ? $plan : $this->_store->getDefaultDomainPlan();
			if ($domainPlan && $this->_store->hasAbilityToPurchaseDomainPlan($domainPlan)) {
				$hasAddDomainAbility = true;
			}
		}
		
		$data = array(
			'id' => $purchase->getId(),
			'type' => __('TRANS_PRODUCT_TYPE_NAME_' . $plan->productType),
			'name' => $purchase->getName(),
			'price' => $price,
			'cycle' => $cycle,
			'hasAvailableAddons' => $hasAddAddonAbility,
			'hasAddDomainAbility' => $hasAddDomainAbility,
			'useTransferFee' => $useTransferFee,
			'fake' => false,
			'purchases' => $subData
		);
		
		return $data;
	}
	
	private function prepareAddonViewData($addon, &$amount, &$totalAmount, &$minimalCycle) {
		
		$billingAddon = ResourceLocator::getInstance()->billingAddonService->getById(
			$addon->getAddonId(),
			$addon->getPlanId(),
			$this->_store->getId(),
			$addon->getCycleId(),
			$addon->hasCoupon() ? $addon->getCoupon()->getId() : false
		);
		
		$price = $billingAddon->getPrice();
		$cycle = $billingAddon->getCycle($price->cycleID);
		if (!$minimalCycle || $minimalCycle->getLength() < $cycle->getLength()) {
			$minimalCycle = $cycle;
		}
		$amount += $price->getTotalFee(true, false);
		$totalAmount += $price->getTotalFee();
		
		return array(
			'id' => $addon->getId(),
			'name' => $billingAddon->productName,
			'price' => $price,
			'cycle' => $cycle
		);
		
	}
	
	private function prepareData(Purchase $purchase, BillingStore $store, BillingPlan $plan, BillingPrice $price) {
		
		$variantId = $price->productVariantID;
		$cycleId = $purchase->getCycleId();
		
		$itemData = $this->prepareItemData($purchase, $price, $plan->productType);
		
		if ($addons = $this->prepareAddonData($purchase, $plan, $store, $cycleId)) {
			$itemData['children'] = $addons;
		}
		
		if ($plan->mayHaveDomains()) {
			
			$domains = array();
			$primaryDomainId = false;
			
			if ($domainData = $purchase->getParameter('domainData')) {
				$primaryDomainId = 0;
				$data = array(
					'shoppingItemsDomainsRelID' => 0,
					'shoppingItemsDomainsType' => 'manual',
					'domainSLD' => $domainData['SLD'],
					'domainTLD' => $domainData['TLD']
				);
				$domains[] = $data;
			}
			
			foreach ($purchase->getPurchases() as $subPurchase) {
				$subPlan = $this->_store->getPlan($subPurchase->getPlanId());
				if ($subPlan->productType == BillingPlan::TYPE_DOMAIN) {
					$data = array(
						'shoppingItemsDomainsRelID' => $subPurchase->getId(),
						'shoppingItemsDomainsType'	=> $subPurchase->getParameter('type'),
						'domainShoppingItemID'		=> $subPurchase->getId()
					);
					$domains[] = $data;
					$primary = false;
					if ($primaryDomainId === false) {
						$primaryDomainId = $subPurchase->getId();
					}
				}
			}
			
			if ($domains) {
				$itemData['domains'] = $domains;
				$itemData['shoppingItemPrimaryDomainID'] = $primaryDomainId;
			}
			
		}
		
		if ($plan->productType == BillingPlan::TYPE_SSL_CERTIFICATE) {
			$itemData['certificates'] = array($this->prepareCertificateData($purchase));
		}
		
		return $itemData;
		
	}
	
	private function prepareDomainData(Purchase $purchase, BillingStore $store, BillingPlan $plan, BillingPrice $price, &$inputParams) {
		
		$variantId = $price->productVariantID;
		$cycleId = $purchase->getCycleId();
		
		$itemData = $this->prepareItemData($purchase, $price, $plan->productType);
		
		if ($addons = $this->prepareAddonData($purchase, $plan, $store, $cycleId)) {
			$itemData['children'] = $addons;
		}
		
		$domainData = $purchase->getParameter('domainData');
		$SLD = $domainData['SLD'];
		$TLD = $domainData['TLD'];
		$domainData = array(
			'shoppingItemDomainType' => $purchase->getParameter('type'),
			'shoppingItemSLD' => $SLD,
			'shoppingItemTLD' => $TLD,
			'shoppingItemDomainLanguage' => false
		);
		$itemData = array_merge($itemData, $domainData);
		
		if (!isset($inputParams['extAttrib'])) {
			$inputParams['extAttrib'] = array();
		}
		$domainName = $SLD . '.' . $TLD;
		$inputParams['extAttrib'][$domainName] = $purchase->getParameter('data');
		
		return $itemData;
		
	}
	
	public function prepareCertificateData(PurchaseContainer $container) {
		$data = $container->getParameter('data');
		$dn = $data['dn'];
		return array(
			'dn' => $dn,
			'csr' => $data['csr'],
			'pkey' => $data['pkey'],
			'webServerType' => $data['webServerType']
		);
	}
	
	private function prepareItemData(PurchaseContainer $container, BillingPrice $price, $planType, $parentId = null) {
		$variantId = $price->productVariantID;
		$cycleId = $container->getCycleId();
		$useTransferFee = $planType == BillingPlan::TYPE_DOMAIN && $container->getParameter('type') == BillingDomainPlan::PURCHASE_TYPE_TRANSFER ? true : false;
		return array(
			'shoppingItemID'			=> $container->getId(),
			'parentShoppingItemID'		=> $parentId,
			'productID'					=> $container instanceof Purchase ? $container->getPlanId() : $container->getAddonId(),
			'productVariantID'			=> $variantId,
			'cycleID'					=> $cycleId,
			'shoppingItemPrice' 		=> $useTransferFee ? $price->getTransferFee(false, false) : $price->getCycleFee(false, false),
			'shoppingItemSetupPrice'	=> $price->getSetupFee(),
			'appliedCouponID'			=> $container->hasCoupon() ? $container->getCoupon()->getId() : null
		);
	}
	
	private function prepareAddonData(Purchase $purchase, BillingPlan $plan, BillingStore $store, $cycleId) {
		$addons = array();
		if ($purchase->hasAddons()) {
			$billingAddons = $plan->getAddons($this->_store->getId(), $cycleId);
			foreach ($purchase->getAddons() as $addon) {
				$billingAddon = isset($billingAddons[$addon->getAddonId()]) ? $billingAddons[$addon->getAddonId()] : null;
				if (!$billingAddon || !$billingAddon->productIsAddon) {
					continue;
				}
				$data = array(
					'shoppingItemID'			=> $addon->getId(),
					'productID'					=> $billingAddon->getId(),
					'productVariantID'			=> $billingAddon->getPrice()->productVariantID,
					'shoppingItemPrice'			=> $billingAddon->getPrice()->getCycleFee(false, false),
					'shoppingItemSetupPrice'	=> $billingAddon->getPrice()->getSetupFee(),
					'appliedCouponID'			=> $addon->hasCoupon() ? $addon->getCoupon()->getId() : null
				);
				$addons[] = $data;
			}
		}
		return $addons;
	}
	
}