public function addProductAdvanced(Mage_Catalog_Model_Product $product, $request = null, $processMode = null)
 {
     if ($request === null) {
         $request = 1;
     }
     if (is_numeric($request)) {
         $request = new Varien_Object(array('qty' => $request));
     }
     if (!$request instanceof Varien_Object) {
         Mage::throwException(Mage::helper('sales')->__('Invalid request for adding product to quote.'));
     }
     switch ($product->getTypeId()) {
         case 'simple':
         case 'virtual':
         case 'downloadable':
         case 'configurable':
         case 'bundle':
             $qty = $request->getQty();
             if ($qty > 1) {
                 $request->setQty(1);
                 for ($i = 1; $i < $qty; $i++) {
                     $lineProduct = clone $product;
                     $lineRequest = clone $request;
                     $this->addProductAdvanced($lineProduct, $lineRequest, $processMode);
                 }
             }
             break;
         case 'grouped':
             $superGroup = $request->getSuperGroup();
             foreach ($superGroup as $productId => $qty) {
                 if ($qty > 1) {
                     for ($i = 1; $i < $qty; $i++) {
                         $customSuperGroup = $request->getSuperGroup();
                         foreach ($customSuperGroup as $customProductId => $customQty) {
                             $customSuperGroup[$customProductId] = $customProductId === $productId ? 1 : 0;
                         }
                         $lineProduct = clone $product;
                         $lineRequest = clone $request;
                         $lineRequest->setSuperGroup($customSuperGroup);
                         $this->addProductAdvanced($lineProduct, $lineRequest, $processMode);
                     }
                 }
                 $superGroup[$productId] = $qty > 0 ? 1 : 0;
             }
             $request->setSuperGroup($superGroup);
             break;
     }
     $cartCandidates = $product->getTypeInstance(true)->prepareForCartAdvanced($request, $product, $processMode);
     /**
      * Error message
      */
     if (is_string($cartCandidates)) {
         return $cartCandidates;
     }
     /**
      * If prepare process return one object
      */
     if (!is_array($cartCandidates)) {
         $cartCandidates = array($cartCandidates);
     }
     $parentItem = null;
     $errors = array();
     $items = array();
     foreach ($cartCandidates as $candidate) {
         // Child items can be sticked together only within their parent
         $stickWithinParent = $candidate->getParentProductId() ? $parentItem : null;
         $candidate->setStickWithinParent($stickWithinParent);
         $item = $this->_addCatalogProduct($candidate, $candidate->getCartQty());
         if ($request->getResetCount() && !$stickWithinParent && $item->getId() === $request->getId()) {
             $item->setData('qty', 0);
         }
         $items[] = $item;
         /**
          * As parent item we should always use the item of first added product
          */
         if (!$parentItem) {
             $parentItem = $item;
         }
         if ($parentItem && $candidate->getParentProductId()) {
             $item->setParentItem($parentItem);
         }
         /**
          * We specify qty after we know about parent (for stock)
          */
         $item->addQty($candidate->getCartQty());
         // collect errors instead of throwing first one
         if ($item->getHasError()) {
             $message = $item->getMessage();
             if (!in_array($message, $errors)) {
                 // filter duplicate messages
                 $errors[] = $message;
             }
         }
     }
     if (!empty($errors)) {
         Mage::throwException(implode("\n", $errors));
     }
     Mage::dispatchEvent('sales_quote_product_add_after', array('items' => $items));
     return $item;
 }