/**
	 * Creates a new (or loads an existing) subscription, and if it's non-free:
	 * Creates a payment basket if there is not already one
	 * ---- and then displays payment processing mask, button, or redirects
	 * If it's free: activates account and does not return anything.
	 *
	 * @param  UserTable           $user
	 * @param  cbpaidProduct[]     $chosenPlans              array of cbpaidProduct : Chosen plans to pay
	 * @param  array               $postdata                 $_POST array for the parameters of the subscription plans
	 * @param  array|null          $replacesSubscriptionIds  In fact: the existing one in all cases, except if new to be created.
	 * @param  array|null          $existingSubscriptionIds  In fact: the new one in case of upgrade !
	 * @param  string              $status 					 subscription status: 'R'=registered (default) , 'I'=illegal, 'A'=active, etc.
	 * @param  string              $prefixText 				 text to prefix the payment items (default: null)
	 * @param  string              $reason 					 payment reason: 'N'=new subscription (default), 'R'=renewal, 'U'=update
	 * @param  string              $payment                  'now' (default), 'free'
	 * @return cbpaidPaymentBasket|string                    object if something to pay, otherwise HTML text for message.
	 */
	public static function createSubscriptionsAndPayment( &$user, $chosenPlans, $postdata, $replacesSubscriptionIds = null, $existingSubscriptionIds = null, $status = 'R', $prefixText = null, $reason='N', $payment = 'now' ) {
		global $_CB_framework, $_CB_database;

		$subscriptionTime				=	$_CB_framework->now();

		/** @var cbpaidSomething[] $subscriptions */
		$subscriptions					=	array();
		$needToPay						=	false;

		//TBD LATER: Handle fully payment baskets as baskets, adding/replacing the content with the new items:
		$paymentBasket					=&	cbpaidPaymentBasket::getInstanceBasketOfUser( $user->id, false );			//TBD could be true to avoid old baskets ?
		if ( $paymentBasket->id ) {
			// otherwise show existing basket:
			return $paymentBasket;
		}

		if ( ! ( $chosenPlans && ( count( $chosenPlans ) > 0 ) ) ) {
			trigger_error( 'createSubscriptionsAndPayment:: called without plans chosen !', E_USER_ERROR );
		}
		// 1. add subscription records if not existing: pass 1: parents, pass 2: children:
		$pass							=	0;
		while ( ++$pass <= 2 ) {
			foreach ( $chosenPlans as $plan ) {
				$parentPlan							=	$plan->get( 'parent' );
				if ( ( ( $pass == 1 ) && ( $parentPlan == 0 ) ) || ( ( $pass == 2 ) && ( $parentPlan != 0 ) ) ) {
					$planId							=	$plan->get( 'id' );

					/* $reasonInCaseExpired			=	$reason; */
					// find replaced subscription id:
					$replacesSubId					=	null;
					if ( $replacesSubscriptionIds && isset( $replacesSubscriptionIds[$planId] ) ) {
						$replacesSubId				=	$replacesSubscriptionIds[$planId];
						/*		//TBD later: need to check if we really want to renew an existing subscription when there is an interruption.
						if ( $reason == 'R' ) {
							$paidSomethinMgr		=&	cbpaidSomethingMgr::getInstance();
							$replacesSub			=&	$paidSomethinMgr->loadSomething( $replacesSubId[0], $replacesSubId[1] );
							if ( $replacesSub ) {
								if ( ! $replacesSub->checkIfValid( $subscriptionTime ) ) {

								}
							}
						}
						*/
					} else {
						if ( $reason == 'R' ) {
							trigger_error( 'createSubscriptionsAndPayment::no existing subscription for renewal !', E_USER_ERROR );
							exit;
						}
					}

					// find existing plan+subscription id:
					$existingSubId					=	null;
					if ( $reason != 'R' ) {
						// new or upgrade: create or load $subscription:
						if ( $existingSubscriptionIds && isset( $existingSubscriptionIds[$planId] ) ) {
							$existingSubId			=	$existingSubscriptionIds[$planId];
						}
					}

					// check that subscription is renewable if getting renewed:
					if ( ( $reason == 'R' ) && $replacesSubId ) {
						$paidSomethingMgr						=&	cbpaidSomethingMgr::getInstance();
						$subscription							=	$paidSomethingMgr->loadSomething( $replacesSubId[0], $replacesSubId[1] );
						if ( ! $subscription->checkIfRenewable() ) {
							trigger_error( sprintf( 'createSubscriptionsAndPayment::Renewal not allowed !' ), E_USER_WARNING );
							return 'Unexpected condition: Renewal not allowed !';
						}
					}
					// find parent subscription id if exists:
					$parentSubId									=	null;
					if ( $parentPlan ) {
						switch ( $reason ) {
							case 'R':
								// renew: don't change anything in the existing subscription (no update on NULL):
								// $parentSubId						=	null;
								break;
							case 'U':
								// upgrade: check if parent subscription is upgraded same time:
								if ( isset( $subscriptions[$parentPlan] ) ) {
									$parentSubId					=	array( (int) $subscriptions[$parentPlan]->plan_id, (int) $subscriptions[$parentPlan]->id );
								} else {
									// if not: try to find the existing subscription in database:
									if ( $existingSubId ) {
										$paidSomethinMgr			=&	cbpaidSomethingMgr::getInstance();
										$thisSub					=	$paidSomethinMgr->loadSomething( $existingSubId[0], $existingSubId[1] );
										if ( $thisSub ) {
											// then try to find parent subscription of the existing subscription:
											if ( $thisSub->parent_plan && $thisSub->parent_subscription ) {
												$thisSubParent		=	$paidSomethinMgr->loadSomething( $thisSub->parent_plan, $thisSub->parent_subscription );
												if ( $thisSubParent ) {
													$parentSubId	=	array( $thisSubParent->parent_plan, $thisSubParent->parent_subscription );
												}
											}
										} else {
											trigger_error( sprintf( 'createSubscriptionsAndPayment::no existing subscription id %d found in database for upgraded plan id %d !', $existingSubId[1], $existingSubId[0] ), E_USER_WARNING );
										}
									} else {
										// try finding subscription of parent plan by this user:
										$plansMgr					=&	cbpaidPlansMgr::getInstance();
										$parPlan					=	$plansMgr->loadPlan( $parentPlan );
										if ( $parPlan ) {
											$something				=	$parPlan->newSubscription();
											$foundParent			=	$something->loadLatestSomethingOfUser( $user->id );
											if ( $foundParent ) {
												$parentSubId		=	array( $something->plan_id, $something->id );
											}
										}
									}
								}
								break;

							case 'N':
							default:
								// new: find parent subscription:
								if ( isset( $subscriptions[$parentPlan] ) ) {
									$parentSubId		=	array( (int) $subscriptions[$parentPlan]->plan_id, (int) $subscriptions[$parentPlan]->id );
								} else {
									trigger_error( sprintf( 'createSubscriptionsAndPayment::no existing subscription for parent plan id %d of plan %d in new subscription !', $parentPlan, $planId ), E_USER_WARNING );
								}
								break;
						}
					}

					// creates the subscription of the correct type:
					$price						=	false;		// returned values from next line:
					$recurringPrice				=	false;		// returned values from next line:
					$subscriptions[$planId]		=	$plan->createProductThing( $user, $postdata, $reason, $status, $replacesSubId, $existingSubId, $subscriptionTime, $price, $recurringPrice, $parentSubId );
					if ( ( $price === false ) && ( $recurringPrice === false ) ) {
						unset( $subscriptions[$planId] );		// can't be subscribed/purchased
						unset( $chosenPlans[$planId] );
					} elseif ( ( $price > 0 ) || ( $recurringPrice > 0 ) ) {
						// $lastSubscriptionId	=	$subscriptions[$planId]->id;
						// $lastPlanId			=	$planId;
						$needToPay				=	true;
					}
				}
			}
		}

		// Sort subscriptions, so they are presented in basket in same order as on the plans selection:
		$sortedSubscriptions					=	array();
		foreach ( array_keys( $chosenPlans ) as $id ) {
			$sortedSubscriptions[$id]			=	$subscriptions[$id];
		}

		if ( ( $payment == 'free' ) || ( ! $needToPay ) ) {						//TBD: Should we activate already what can be activated (check for hierarchy) !???
			// Free plan: no payment ! : activate $subscription now:
			$thankYouText						=	array();
			$cbUser								=	CBuser::getInstance( $user->id );
			foreach ( array_keys( $subscriptions ) as $k ) {
				if ( ( $reason != 'R' ) || $subscriptions[$k]->checkIfRenewable() ) {
					$occurrences				=	1;
					$autorecurring_type			=	0;
					$autorenew_type				=	0;
					// bug #1184 fix: this was certainly wrong in backend at least, but in frontend too most likely too, as it would block from renewing imho:
					// $autorecurring_type			=	( ( $chosenPlans[$k]->autorecurring > 0 ) ? 2 : 0 );
					// $autorenew_type				=	( ( $chosenPlans[$k]->autorecurring > 0 ) ? 2 : 0 );
					$subscriptions[$k]->activate( $user, $subscriptionTime, true, $reason, $occurrences, $autorecurring_type, $autorenew_type );
					$extraStrings				=	$subscriptions[$k]->substitutionStrings( true );
					$thankYouText[]				=	trim( $cbUser->replaceUserVars( CBPTXT::Th( $subscriptions[$k]->getText( 'thankyoutextcompleted' ) ), true, true, $extraStrings, false ) );
				}
			}
			if ( count( $thankYouText ) > 0 ) {
				return implode( '<br />', $thankYouText );
			} else {
				return CBPTXT::Th("Chosen plan(s) can not be subscribed") . '.';
			}
		} else {
			// non-free plan:
			// 2. add payment_item and payment_basket records:

			// get the most recent payment basket for $subscription
			$paymentBasket						=	new cbpaidPaymentBasket( $_CB_database );
			/*
						$basketLoaded						=	$paymentBasket->loadLatestBasketOfUserPlanSubscription( $user->id );
						if ( $basketLoaded ) {
							$paymentBasket->delete();
							$paymentBasket					=	new cbpaidPaymentBasket( $_CB_database );
							//TBD LATER: Handle fully payment baskets as baskets, adding/replacing the content with the new items.
						}
			*/
			$hasAmountToPay						=	$paymentBasket->createAndFillCreteSubscriptionsItems( $user, $sortedSubscriptions, $prefixText, $reason, $subscriptionTime );
			if ( ! $hasAmountToPay ) {
				$thankYouText					=	array();
				$cbUser							=	CBuser::getInstance( $user->id );
				foreach ( array_keys( $subscriptions ) as $k ) {
					$subscriptions[$k]->activate( $user, $subscriptionTime, true, $reason );
					$extraStrings				=	$subscriptions[$k]->substitutionStrings( true );
					$thankYouText[]				=	trim( $cbUser->replaceUserVars( CBPTXT::Th( $subscriptions[$k]->getText( 'thankyoutextcompleted' ) ), true, true, $extraStrings, false ) );
				}
				return implode( '<br />', $thankYouText );
			}

			if ( ( $paymentBasket->payment_status === null ) || ( $paymentBasket->payment_status == 'NotInitiated' ) ) {
				return $paymentBasket;
			}
		}
		trigger_error( '_createSubscriptionsAndPayment: Unexpected condition: no payment and no free plan', E_USER_NOTICE );
		return 'Unexpected condition.';
	}