/**
  * @return Double
  **/
 protected function LiveCalculatedTotal()
 {
     //________________ start caching mechanism
     if (self::$calculations_done) {
         return self::$actual_charges;
     }
     self::$calculations_done = true;
     //________________ end caching mechanism
     self::$actual_charges = 0;
     //do we have enough information
     $obj = $this->liveOptionObject();
     if ($items = $this->Order()->Items() && is_object($obj) && $obj->exists()) {
         $this->debugMessage .= "<hr />option selected: " . $obj->Title . ", and items present";
         //lets check sub-total
         $subTotalAmount = $this->LiveSubTotalAmount();
         $this->debugMessage .= "<hr />sub total amount is: \$" . $subTotalAmount;
         // no need to charge, order is big enough
         $minForZeroRate = floatval($obj->MinimumOrderAmountForZeroRate);
         $maxForZeroRate = floatval($obj->FreeShippingUpToThisOrderAmount);
         if ($minForZeroRate > 0 && $minForZeroRate < $subTotalAmount) {
             self::$actual_charges = 0;
             $this->debugMessage .= "<hr />Minimum Order Amount For Zero Rate: " . $obj->MinimumOrderAmountForZeroRate . " is lower than amount  ordered" . self::$actual_charges;
         } elseif ($maxForZeroRate > 0 && $maxForZeroRate > $subTotalAmount) {
             self::$actual_charges = 0;
             $this->debugMessage .= "<hr />Maximum Order Amount For Zero Rate: " . $obj->FreeShippingUpToThisOrderAmount . " is higher than amount ordered" . self::$actual_charges;
         } else {
             $weight = $this->LiveTotalWeight();
             if ($weight) {
                 $this->debugMessage .= "<hr />there is weight: {$weight}gr.";
                 //weight brackets
                 $weightBrackets = $obj->WeightBrackets();
                 $foundWeightBracket = null;
                 $weightBracketQuantity = 1;
                 $additionalWeightBracket = null;
                 if ($weightBrackets && $weightBrackets->Count()) {
                     $minimumMinimum = null;
                     $maximumMaximum = null;
                     foreach ($weightBrackets as $weightBracket) {
                         if (!$foundWeightBracket && $weightBracket->MinimumWeight <= $weight && $weight <= $weightBracket->MaximumWeight) {
                             $foundWeightBracket = $weightBracket;
                         }
                         //look for absolute min and max
                         if ($minimumMinimum == null || $weightBracket->MinimumWeight > $minimumMinimum->MinimumWeight) {
                             $minimumMinimum = $weightBracket;
                         }
                         if ($maximumMaximum == null || $weightBracket->MaximumWeight > $maximumMaximum->MaximumWeight) {
                             $maximumMaximum = $weightBracket;
                         }
                     }
                     if (!$foundWeightBracket) {
                         if ($weight < $minimumMinimum->MinimumWeight) {
                             $foundWeightBracket = $minimumMinimum;
                         } elseif ($weight > $maximumMaximum->MaximumWeight) {
                             $foundWeightBracket = $maximumMaximum;
                             $weightBracketQuantity = floor($weight / $maximumMaximum->MaximumWeight);
                             $restWeight = $weight - $maximumMaximum->MaximumWeight * $weightBracketQuantity;
                             $additionalWeightBracket = null;
                             foreach ($weightBrackets as $weightBracket) {
                                 if ($weightBracket->MinimumWeight <= $restWeight && $restWeight <= $weightBracket->MaximumWeight) {
                                     $additionalWeightBracket = $weightBracket;
                                     break;
                                 }
                             }
                         }
                     }
                 }
                 //we found some applicable weight brackets
                 if ($foundWeightBracket) {
                     self::$actual_charges += $foundWeightBracket->FixedCost * $weightBracketQuantity;
                     $this->debugMessage .= "<hr />found Weight Bracket (from {$foundWeightBracket->MinimumWeight}gr. to {$foundWeightBracket->MaximumWeight}gr.): \${$foundWeightBracket->FixedCost} ({$foundWeightBracket->Name}) from  times {$weightBracketQuantity}";
                     if ($additionalWeightBracket) {
                         self::$actual_charges += $additionalWeightBracket->FixedCost;
                         $this->debugMessage .= "<hr />+ additional Weight Bracket (from {$additionalWeightBracket->MinimumWeight}gr. to {$additionalWeightBracket->MaximumWeight}gr.): \${$additionalWeightBracket->FixedCost} ({$foundWeightBracket->Name})";
                     }
                 } elseif ($weight && $obj->WeightMultiplier) {
                     // add weight based shipping
                     if (!$obj->WeightUnit) {
                         $obj->WeightUnit = 1;
                     }
                     $this->debugMessage .= "<hr />actual weight:" . $weight . " multiplier = " . $obj->WeightMultiplier . " weight unit = " . $obj->WeightUnit . " ";
                     //legacy fix
                     $units = ceil($weight / $obj->WeightUnit);
                     $weightCharge = $units * $obj->WeightMultiplier;
                     self::$actual_charges += $weightCharge;
                     $this->debugMessage .= "<hr />weight charge: " . $weightCharge;
                 }
             }
             // add percentage
             if ($obj->Percentage) {
                 $percentageCharge = $subTotalAmount * $obj->Percentage;
                 self::$actual_charges += $percentageCharge;
                 $this->debugMessage .= "<hr />percentage charge: \$" . $percentageCharge;
             }
             // add fixed price
             if ($obj->FixedCost != 0) {
                 self::$actual_charges += $obj->FixedCost;
                 $this->debugMessage .= "<hr />fixed charge: \$" . $obj->FixedCost;
             }
             //is it enough?
             if (self::$actual_charges < $obj->MinimumDeliveryCharge && $obj->MinimumDeliveryCharge > 0) {
                 $oldActualCharge = self::$actual_charges;
                 self::$actual_charges = $obj->MinimumDeliveryCharge;
                 $this->debugMessage .= "<hr />too little: actual charge: " . $oldActualCharge . ", minimum delivery charge: " . $obj->MinimumDeliveryCharge;
             }
             // is it too much
             if (self::$actual_charges > $obj->MaximumDeliveryCharge && $obj->MaximumDeliveryCharge > 0) {
                 self::$actual_charges = $obj->MaximumDeliveryCharge;
                 $this->debugMessage .= "<hr />too much: " . self::$actual_charges . ", maximum delivery charge is " . $obj->MaximumDeliveryCharge;
             }
         }
     } else {
         if (!$items) {
             $this->debugMessage .= "<hr />no items present";
         } else {
             $this->debugMessage .= "<hr />no delivery option available";
         }
     }
     $this->debugMessage .= "<hr />final score: \$" . self::$actual_charges;
     //special case, we are using weight and there is no weight!
     return self::$actual_charges;
 }