/**
	 * returns HTML code to show the currently subscribed plans
	 * @access private
	 *
	 * @param  int                             $now                     Unix-time
	 * @param  UserTable                       $user                    Reflecting the user being displayed
	 * @param  cbpaidUsersubscriptionRecord[]  $subscriptions           array of cbpaidUsersubscriptionRecord : subscriptions already checked by getUpgradeAndRenewalPossibilities()
	 * @param  string                          $plansTitle
	 * @param  boolean                         $showRenewButtons        Draw the Renew and Resubscribe buttons
	 * @param  boolean                         $showUnsubscribeButtons  Draw the Unsubscribe button
	 * @return string                                                   HTML for display
	 */
	protected function _getSubscribedPlans( /** @noinspection PhpUnusedParameterInspection */ $now, &$user, &$subscriptions, $plansTitle, $showRenewButtons, $showUnsubscribeButtons ) {	//TBD: most of this belongs to subscriptionsMgr object
		global $_CB_framework, $_PLUGINS;

		$_PLUGINS->loadPluginGroup( 'user', 'cbsubs.' );
		$_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');

		$return							=	null;
		if ( count($subscriptions) > 0 ) {
			$now						=	$_CB_framework->now();

			$return .= "\n<div class='regPlansList' id='cbregSubscr'>";

			$subIds						=	array_reverse( array_keys( $subscriptions ) );		// get plans in reverse order to draw all children first
			$children					=	array();
			foreach ( $subIds AS $id ) {
				if ( isset( $children[(int) $subscriptions[$id]->getPlanAttribute( 'id' )] ) ) {
					$childrenRendering	=	implode( "\n", $children[(int) $subscriptions[$id]->getPlanAttribute( 'id' )] );
					unset( $children[(int) $subscriptions[$id]->getPlanAttribute( 'id' )] );
				} else {
					$childrenRendering	=	null;
				}
				
				$controlButtons			=	$this->_drawSubscriptionButtons( $subscriptions[$id], $showRenewButtons, $showUnsubscribeButtons, $now, $user );

				$_PLUGINS->trigger( 'onCPayBeforeDrawSomething', array( &$subscriptions[$id], &$childrenRendering, &$controlButtons, $showRenewButtons, $showUnsubscribeButtons, $now, $user ) );

				$childrenRendering		.=	$controlButtons;
				$template				=	$subscriptions[$id]->getPlan()->getTemplateOutoutCss();
				/** @var $view cbpaidSomethingView */
				$view					=	cbpaidTemplateHandler::getViewer( $template, 'something' );
				$view->setModel( $subscriptions[$id] );
				$render					=	$view->drawSomethingNameDescription( $now, $childrenRendering );

				$_PLUGINS->trigger( 'onCPayAfterDrawSomething', array( &$subscriptions[$id], &$render, $now, $user ) );

				if ( ! isset( $children[(int) $subscriptions[$id]->getPlanAttribute( 'parent' )] ) ) {
					$children[(int) $subscriptions[$id]->getPlanAttribute( 'parent' )]	=	array();
				}
				array_unshift( $children[(int) $subscriptions[$id]->getPlanAttribute( 'parent' )], $render );
			}
			foreach ( array_keys( $children ) as $k ) {
				$children[$k]			=	implode( "\n", $children[$k] );
			}
			$return						.=	implode( "\n", $children )
										.	"\n";
			$return .= "</div>\n";
		}
		return $return;
	}
 /**
  * Outputs cbpaidsubscriptions registration template CSS file
  *
  * @param  string   $template  Template to use (default is 'default')
  * @return void
  */
 public function outputRegTemplate($template = '')
 {
     global $_CB_framework;
     static $dones = array();
     if (!isset($dones[$template])) {
         $inBackend = $_CB_framework->getUi() == 2;
         if (!$inBackend || $template == '') {
             cbpaidTemplateHandler::getViewer($inBackend ? 'default' : $template, null)->outputTemplateCss('cbpaidsubscriptions');
             if ($inBackend) {
                 $_CB_framework->document->addHeadStyleSheet('/components/com_comprofiler/plugin/user/plug_cbpaidsubscriptions/templates/default/cbpaidsubscriptions.admin.css');
             }
         }
         $dones[$template] = true;
     }
 }
	/**
	 * Render the payment possibilities as radios, buttons, or URL for redirect of browser
	 *
	 * @param  cbpaidPaymentRadio[][]      $payChoicesHtmlArray
	 * @param  cbpaidPaymentBasket         $paymentBasket
	 * @param  string                      $redirectNow
	 * @param  string                      $chosenPaymentMethod
	 * @param  array                       $payChoicesHtmlRadiosArray  OUT
	 * @param  cbpaidGatewaySelector|null  $chosenPaymentSelector      OUT
	 * @return string
	 */
	private function _renderPayChoicesArray( $payChoicesHtmlArray, $paymentBasket, $redirectNow, $chosenPaymentMethod, &$payChoicesHtmlRadiosArray, &$chosenPaymentSelector ) {
		$ret										=	array();
		$chosenPaymentSelector						=	null;

		if ( ( $redirectNow == 'redirect' ) || ( $redirectNow === true ) ) {
			foreach ( $payChoicesHtmlArray as $drawParams ) {
				if ( is_array( $drawParams ) ) {
					if ( is_string( $drawParams[0] ) ) {
						// Redirect is possible: Just return URL:
						$ret						=	$drawParams[0];
					} else {
						// Redirect is wished but instead we got a button, as redirect was not possible (e.g. URL > 2k IE limit with Paypal encrypted payments):
						/** @var $renderer cbpaidBasketView */
						$renderer					=	cbpaidTemplateHandler::getViewer( null, 'basket' );
						$ret[]						=	$renderer->drawPaymentButton( $drawParams[0] );
					}
				}
			}
		} elseif ( $redirectNow == 'radios' ) {
			$payment_method_radios_template			=	cbpaidApp::settingsParams()->get( 'payment_method_radios_template', '' );
			/** @var $renderer cbpaidBasketView */
			$renderer								=	cbpaidTemplateHandler::getViewer( $payment_method_radios_template, 'basket' );
			$renderer->setModel( $paymentBasket );
			foreach ( $payChoicesHtmlArray as $gatewaySubMethods ) {
				if ( is_array( $gatewaySubMethods ) ) {
					foreach ( $gatewaySubMethods as $radioPaymentSelector ) {
						/** @var $radioPaymentSelector cbpaidGatewaySelectorRadio */
						$radioValue					=	$radioPaymentSelector->radioValue();
						$selected					=	( $chosenPaymentMethod === $radioValue );
						if ( $selected ) {
							$chosenPaymentSelector	=	$radioPaymentSelector;
						}
						$payChoicesHtmlRadiosArray[] =	array( $selected, $renderer->drawPaymentRadio( $radioPaymentSelector, $selected ) );
					}
				} elseif ( is_string( $gatewaySubMethods ) ) {
					$ret[]							=	$gatewaySubMethods;
				}
			}
		} else {
			/** @var $renderer cbpaidBasketView */
			$renderer								=	cbpaidTemplateHandler::getViewer( null, 'basket' );
			$renderer->setModel( $paymentBasket );
			foreach ( $payChoicesHtmlArray as $gatewaySubMethods ) {
				if ( is_array( $gatewaySubMethods ) ) {
					foreach ( $gatewaySubMethods as $paymentButton ) {
						$ret[]						=	$renderer->drawPaymentButton( $paymentButton );
					}
				} elseif ( is_string( $gatewaySubMethods ) ) {
					$ret[]							=	$gatewaySubMethods;
				}
			}
		}
		return $ret;
	}
 /**
  * Constructor
  *
  * @param  array  $invoices   model
  */
 public function __construct($invoices)
 {
     parent::__construct();
     $this->_model = $invoices;
 }
 /**
  * Draws a subscription's name and description...
  *
  * @param  int|null $now                     unix time for the expiration times (null: now)
  * @param  string   $insertAfterDescription  HTML text to insert after this item as sub-items
  * @param  boolean  $showStateCheckMark
  * @return string
  */
 public function drawSomethingNameDescription($now, $insertAfterDescription, $showStateCheckMark = true)
 {
     global $_CB_framework, $_PLUGINS;
     /** @var $subscription cbpaidUsersubscriptionRecord */
     $subscription = $this->_model;
     $params = cbpaidApp::settingsParams();
     $showtime = $params->get('showtime', '1') == '1';
     $subTxt = CBPTXT::T($params->get('subscription_name', 'subscription'));
     $titlesTexts = array('A' => sprintf(CBPTXT::T("Active %s"), $subTxt), 'AA' => sprintf(CBPTXT::T("Active %s"), $subTxt), 'R' => sprintf(CBPTXT::T("%s not yet paid"), ucfirst($subTxt)), 'U' => sprintf(CBPTXT::T("Upgraded %s"), $subTxt), 'C' => sprintf(CBPTXT::T("Unsubscribed %s"), $subTxt), 'X' => sprintf(CBPTXT::T("Expired %s"), $subTxt), 'XX' => sprintf(CBPTXT::T("Inactive (parent %s not active)"), $subTxt), 'ZZ' => sprintf(CBPTXT::T("Unknown state of %s"), $subTxt));
     // local state
     //TODO use getFormattedExpirationDateText()
     $stateTexts = array('A' => CBPTXT::T("Active"), 'AA' => CBPTXT::T("Active, expiring on %s"), 'R' => CBPTXT::T("Not yet paid"), 'U' => CBPTXT::T("Upgraded to higher plan on %s"), 'C' => CBPTXT::T("Unsubscribed on %s"), 'X' => CBPTXT::T("Expired %s"), 'XX' => sprintf(CBPTXT::T("Inactive (parent %s not active)"), $subTxt), 'ZZ' => sprintf(CBPTXT::T("Unknown state of %s"), $subTxt));
     // local state
     $autoRenewingText = CBPTXT::T("%s, auto-renewing");
     $autoRenewingXtimes = CBPTXT::T("%s, auto-renewing %s more times until %s");
     // check if active and if parents are active:
     $realStatus = $subscription->realStatus($now);
     $subActive = $subscription->checkIfValid($now);
     $subAndParentsActive = $subscription->checkIfThisAndParentSubscriptionIsValid($now);
     if ($subActive && !$subAndParentsActive) {
         $status = 'XX';
     } else {
         // compute local pseudo status, which is subscription status and 2 local states: AA and ZZ:
         $status = $realStatus;
         if (!array_key_exists($realStatus, $titlesTexts)) {
             $status = 'ZZ';
         }
         if ($status == 'A' && !$subscription->isLifetimeValidity()) {
             $status = 'AA';
         }
     }
     if ($status == 'ZZ' && $_CB_framework->getUi() == 1) {
         // if status is unknown, don't display it in frontend, only in backend !
         return $insertAfterDescription;
     }
     $viewModel = new cbpaidSomethingViewModel();
     $viewModel->subscription = $subscription;
     $viewModel->name = $subscription->getPlan()->getPersonalized('name', $subscription->user_id, true);
     $viewModel->description = $subscription->getPlan()->getPersonalized('description', $subscription->user_id, true);
     $viewModel->cssclass = $subscription->getPlanAttribute('cssclass');
     $viewModel->active = $subAndParentsActive;
     $viewModel->validity = htmlspecialchars($subscription->getFormattedValidityRemaining());
     $viewModel->title = htmlspecialchars($titlesTexts[$status]);
     // Prepare the exact description text for the status:
     if ($subscription->expiry_date && !($subscription->status == 'X' && $subActive)) {
         $expDate = cbFormatDate($subscription->expiry_date, 1, $showtime);
     } else {
         $expDate = '';
     }
     $stateText = sprintf($stateTexts[$status], $expDate);
     // add information of auto-renewals if autorecurring and all autorecurrings are not yet done:
     if ($subscription->autorecurring_type > 0 && $status == 'AA' && ($subscription->regular_recurrings_total == 0 || $subscription->regular_recurrings_used < $subscription->regular_recurrings_total)) {
         if ($subscription->autorecurring_type == 2 && $subscription->regular_recurrings_total && $subscription->regular_recurrings_used < $subscription->regular_recurrings_total) {
             $occurrences = $subscription->regular_recurrings_total - $subscription->regular_recurrings_used;
             $finalExpTime = $subscription->computeExpiryTimeIfActivatedNow($now, 'R', $occurrences);
             $finalExpTxt = cbFormatDate($finalExpTime, 1, $showtime);
             // '%s, auto-renewing %s more times until %s' :
             $stateText = sprintf($autoRenewingXtimes, $stateText, $occurrences, $finalExpTxt);
         } else {
             // '%s, auto-renewing' :
             $stateText = sprintf($autoRenewingText, $stateText);
         }
     }
     $viewModel->stateText = htmlspecialchars($stateText);
     //TBD ???? $plan->displayPeriodPrice( 'R', $sub->getOccurrence() + 1, null, $plan->strToTime( $sub->expiry_date ), false );
     $_PLUGINS->loadPluginGroup('user', 'cbsubs.');
     $_PLUGINS->loadPluginGroup('user/plug_cbpaidsubscriptions/plugin');
     $insertBeforeValidity = implode('', $_PLUGINS->trigger('onCPayBeforeDrawSubscription', array(&$viewModel, &$subscription, &$insertAfterDescription)));
     /** @var $view cbpaidsomethingusersubscriptionView */
     $view = cbpaidTemplateHandler::getViewer($this->templateToUse(), 'somethingusersubscription', 'html');
     //TBD extend to any Something (merchandises, donations)
     $view->setModel($viewModel);
     return $view->drawSomething($insertBeforeValidity, $insertAfterDescription, $showStateCheckMark);
 }
	/**
	 * Displays user subscription and link to invoice HTML (if allowed)
	 *
	 * @param  UserTable  $user
	 * @param  string     $htmlTabDescription
	 * @return string
	 */
	public function displaySubscriptionsAndInvoicesLink( $user, $htmlTabDescription = null ) {
		global $_CB_framework;

		$return					=	'';
		$params					=	$this->params;

		$itsmyself				=	( $_CB_framework->myId() == $user->id );
		$displayToMe			=	$itsmyself;
		if ( ! $itsmyself ) {
			$displayToMe		=	cbpaidApp::authoriseAction( 'cbsubs.usersubscriptionview' );
			if ( $displayToMe ) {
				$itsmyself		=	cbpaidApp::authoriseAction( 'cbsubs.usersubscriptionmanage' );
			}
		}
		if ( $user->id && $displayToMe ) {

			$basketsMgr				=&	cbpaidOrdersMgr::getInstance();
			$basketsMgr->timeoutUnusedBaskets( $user->id );

			$subscriptionsGUI		=	new cbpaidControllerUI();
			$htmlSubscriptionsAndUpgrades =	$subscriptionsGUI->getShowSubscriptionUpgrades( $user, $itsmyself );

			$htmlInvoicesLink		=	null;
			$showInvoices			=	$params->get( 'show_invoices', 1 );
			$invoicesShowPeriod		=	$params->get( 'invoices_show_period', '0000-06-00 00:00:00' );
			if ( $showInvoices ) {
				$invoicesNumber		=	$this->_getInvoices( $user, $invoicesShowPeriod, true );
				if ( $invoicesNumber > 0 ) {
					$invoicesListUrl =	$this->getInvoicesListUrl( $user );
					if ( $invoicesShowPeriod && ( $invoicesShowPeriod != '0000-00-00 00:00:00' ) ) {
						$cbpaidTimes	=&	cbpaidTimes::getInstance();
						$periodText		=	$cbpaidTimes->renderPeriod( $invoicesShowPeriod, 1, false );
					} else {
						$periodText		=	'';
					}
					$htmlInvoicesLink	=	$subscriptionsGUI->showInvoicesListLink( $invoicesNumber, $invoicesListUrl, $user, $itsmyself, $periodText );
				}
			}

			$tabTitleText			=	$params->get( 'profileTitle', "Your subscriptions" );

			/** @var $viewer cbpaiduserprofilesubstabView */
			$viewer					=	cbpaidTemplateHandler::getViewer( null, 'userprofilesubstab' );
			$viewer->setModel( $user );
			$return					.=	$viewer->drawTab( $htmlSubscriptionsAndUpgrades, $htmlInvoicesLink, $tabTitleText, $htmlTabDescription );
		}
		return $return;
	}
	/**
	 * Generates the HTML to display the registration tab/area
	 *
	 * @param  TabTable   $tab       the tab database entry
	 * @param  UserTable  $user      the user being displayed
	 * @param  int        $ui        1 for front-end, 2 for back-end
	 * @param  array      $postdata  _POST data for saving edited tab content as generated with getEditTab
	 * @return string|boolean        Either string HTML for tab content, or false if ErrorMSG generated
	 */
	public function getDisplayRegistration( $tab, $user, $ui, $postdata ) {
		cbpaidErrorHandler::on();
		$return							=	'';


		$params							=	$this->params;
		$registrationPlansEnabled		=	$params->get('registrationPlansEnabled', 0);

		if ($registrationPlansEnabled) {
			$this->outputRegTemplate();

			$subscriptionsGUI			=	new cbpaidControllerUI();
			$plansTitle					=	CBPTXT::T( $this->params->get( 'regTitle', "Subscriptions" ) );
			
			$htmlPlans					=	$subscriptionsGUI->getShowRegistrationPlans( $user, $plansTitle, 'N' );
			/** @var $viewer cbpaiduserregistrationplansView */
			$viewer						=	cbpaidTemplateHandler::getViewer( null, 'userregistrationplans' );
			$viewer->setModel( $tab );
			$return						=	$viewer->drawRegistrationPlans( $plansTitle, $htmlPlans );

		}
		cbpaidErrorHandler::off();
		return $return;
	}
 /**
  * Constructor
  *
  * @param  cbpaidProduct  $model
  */
 public function __construct($model)
 {
     parent::__construct();
     $this->_model = $model;
 }
	/**
	 * Cancels an existing recurring subscription
	 *
	 * @param  cbpaidPaymentBasket  $paymentBasket  paymentBasket object
	 * @param  cbpaidPaymentItem[]  $paymentItems   redirect immediately instead of returning HTML for output
	 * @return boolean|string                       TRUE if unsubscription done successfully, STRING if error
	 */
	protected function handleStopPaymentSubscription( $paymentBasket, $paymentItems )
	{
		global $_CB_framework, $_CB_database;

		if ( $paymentBasket->mc_amount3 ) {
			// Recurring amount existing and if first amount existed it got payed OK: subscribe to an ARB:
			if ( $paymentBasket->subscr_id ) {
				
				if ( $this->hasPaypalApi() /* && ( substr( $paymentBasket->subscr_id, 0, 2 ) != 'S-' ) */ ) {			// Only subscription ids starting with I- can be handled through API for unsubscription: S- subscriptions can not.
					// There is an API access, let's try to use it:

					$return						=	$this->getPaypalApi()->ManageRecurringPaymentsProfileStatus( $paymentBasket->subscr_id, 'cancel', null );
					if ( $return ) {
						// Success! : $return is TRUE:
						$ipn					=	new cbpaidPaymentNotification( $_CB_database );
						$ipn->payment_method	=	$this->getPayName();
						$ipn->gateway_account	=	$this->getAccountParam( 'id' );
						$ipn->log_type			=	'5';
						$ipn->time_received		=	date( 'Y-m-d H:i:s', $_CB_framework->now() );
						$ipn->raw_data			=	/* cbGetParam() not needed: we want raw info */ '$_GET=' . var_export( $_GET, true ) . ";\n";
						$ipn->raw_data			.=	/* cbGetParam() not needed: we want raw info */ '$_POST=' . var_export( $_POST, true ) . ";\n";
						$ipn->raw_data			.=	$this->getPaypalApi()->getRawLogData() . ";\n";
						$ipn->ip_addresses		=	cbpaidRequest::getIPlist();
						$ipn->payment_basket_id	=	$paymentBasket->id;
						$ipn->user_id			=	$paymentBasket->user_id;
						$_CB_database->insertObject( $ipn->getTableName(), $ipn, $ipn->getKeyName() );

					} else {
						$this->setLogPaypalApiErrors( $paymentBasket );
						$return					=	'';
					}
				} else {
					$return						=	'';
				}
				if ( ! $return ) {
					// No API, we can only render a button: (which is not displayed in case of upgrades):

					if ( ! is_string( $return ) ) {
						$return					=	'';
					}

					$return						.=	CBPTXT::Th("You are currently using PayPal  Recurring Payments to pay for your subscription. To unsubscribe and stop future payments, you must to do this from Paypal. Click on the button below to login into PayPal and follow the instructions there to unsubscribe. This will automatically stop your subscription on this site.");
	
					$paymentButton				=	$this->getPayButtonRecepie( $paymentBasket, 'subscribe', 'cancel' );
	
					// Needed to post the button:
					$subscriptionsGUI					=	new cbpaidControllerUI();
					$subscriptionsGUI->addcbpaidjsplugin();

					/** @var $renderer cbpaidBasketView */
					$renderer					=	cbpaidTemplateHandler::getViewer( null, 'basket' );
					$renderer->setModel( $paymentBasket );
					$return						.=	$renderer->drawPaymentButton( $paymentButton );
				}
			} else {
				$this->_setLogErrorMSG( 3, null, 'Paypal autorecurring payment subscriptions: stopPaymentSubscription error: missing subscr_id in payment basket', CBPTXT::T("Submitted unsubscription didn't return an error but didn't complete.") );
				$return							=	'';
			}
		} else {
			$return								=	CBPTXT::T("Unsubscription from payment processor is not possible as this payment basket has no autorecurring amount.");
		}
		return $return;
	}
	/**
	 * Gets the viewer class for the rendering, keeps it in cache.
	 *
	 * @return cbpaidProductView
	 */
	public function & getViewer( ) {
		if ( ! isset( $this->_viewer ) ) {
			$template		=	$this->getTemplateOutoutCss();
			$view			=	'product' . $this->item_type;
			$output			=	'html';			// For now...
			$this->_viewer	=	cbpaidTemplateHandler::getViewer( $template, $view, $output );
			$this->_viewer->setModel( $this );
		}
		return $this->_viewer;
	}
	/**
	 * parses regex match callback plan substitutions
	 *
	 * @param  array   $matches
	 * @return string
	 */
	public function replacePlanSubstitutions( $matches ) {
		$planId					=	( isset( $matches[1] ) ? (int) $matches[1] : null );
		$text					=	( isset( $matches[2] ) ? $matches[2] : null );

		if ( $planId && $text ) {
			$user				=	cbUser::getMyUserDataInstance();
			$plansMgr			=	cbpaidPlansMgr::getInstance();
			$plan				=	$plansMgr->getPublishedPlan( $planId, $user );

			if ( $plan ) {
				// Output CSS for displaying the plan properly:
				cbpaidTemplateHandler::getViewer( '', null )->outputTemplateCss( 'cbpaidsubscriptions' );
				$plan->getTemplateOutoutCss();

				// Get substitutions:
				return $plan->getPersonalized( $text, $user->id, true, true, null, false );
			}
		}

		return null;
	}