/**
  * Handles saving everything related to Tickets (datetimes, tickets, prices)
  * @param  EE_Event $evtobj The Event object we're attaching data to
  * @param  array    $data   The request data from the form
  * @return bool             success or fail
  */
 protected function _default_tickets_update(EE_Event $evtobj, $data)
 {
     $success = true;
     $saved_dtt = null;
     $saved_tickets = array();
     $incoming_date_formats = array('Y-m-d', 'h:i a');
     foreach ($data['edit_event_datetimes'] as $row => $dtt) {
         //trim all values to ensure any excess whitespace is removed.
         $dtt = array_map('trim', $dtt);
         $dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && !empty($dtt['DTT_EVT_end']) ? $dtt['DTT_EVT_end'] : $dtt['DTT_EVT_start'];
         $datetime_values = array('DTT_ID' => !empty($dtt['DTT_ID']) ? $dtt['DTT_ID'] : NULL, 'DTT_EVT_start' => $dtt['DTT_EVT_start'], 'DTT_EVT_end' => $dtt['DTT_EVT_end'], 'DTT_reg_limit' => empty($dtt['DTT_reg_limit']) ? EE_INF : $dtt['DTT_reg_limit'], 'DTT_order' => $row);
         //if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
         if (!empty($dtt['DTT_ID'])) {
             $DTM = EE_Registry::instance()->load_model('Datetime', array($evtobj->get_timezone()))->get_one_by_ID($dtt['DTT_ID']);
             $DTM->set_date_format($incoming_date_formats[0]);
             $DTM->set_time_format($incoming_date_formats[1]);
             foreach ($datetime_values as $field => $value) {
                 $DTM->set($field, $value);
             }
             //make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
             $saved_dtts[$DTM->ID()] = $DTM;
         } else {
             $DTM = EE_Registry::instance()->load_class('Datetime', array($datetime_values), FALSE, FALSE);
             $DTM->set_date_format($incoming_date_formats[0]);
             $DTM->set_time_format($incoming_date_formats[1]);
             $DTM->set_timezone($evtobj->get_timezone());
             foreach ($datetime_values as $field => $value) {
                 $DTM->set($field, $value);
             }
         }
         $DTM->save();
         $DTT = $evtobj->_add_relation_to($DTM, 'Datetime');
         //load DTT helper
         //before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
         if ($DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end')) {
             $DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start'));
             $DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
             $DTT->save();
         }
         //now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
         $saved_dtt = $DTT;
         $success = !$success ? $success : $DTT;
         //if ANY of these updates fail then we want the appropriate global error message. //todod this is actually sucky we need a better error message but this is what it is for now.
     }
     //no dtts get deleted so we don't do any of that logic here.
     //update tickets next
     $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
     foreach ($data['edit_tickets'] as $row => $tkt) {
         $incoming_date_formats = array('Y-m-d', 'h:i a');
         $update_prices = false;
         $ticket_price = isset($data['edit_prices'][$row][1]['PRC_amount']) ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
         // trim inputs to ensure any excess whitespace is removed.
         $tkt = array_map('trim', $tkt);
         if (empty($tkt['TKT_start_date'])) {
             //let's use now in the set timezone.
             $now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
             $tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
         }
         if (empty($tkt['TKT_end_date'])) {
             //use the start date of the first datetime
             $dtt = $evtobj->first_datetime();
             $tkt['TKT_end_date'] = $dtt->start_date_and_time($incoming_date_formats[0], $incoming_date_formats[1]);
         }
         $TKT_values = array('TKT_ID' => !empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : NULL, 'TTM_ID' => !empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0, 'TKT_name' => !empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '', 'TKT_description' => !empty($tkt['TKT_description']) ? $tkt['TKT_description'] : '', 'TKT_start_date' => $tkt['TKT_start_date'], 'TKT_end_date' => $tkt['TKT_end_date'], 'TKT_qty' => !isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === '' ? EE_INF : $tkt['TKT_qty'], 'TKT_uses' => !isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === '' ? EE_INF : $tkt['TKT_uses'], 'TKT_min' => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'], 'TKT_max' => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'], 'TKT_row' => $row, 'TKT_order' => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : $row, 'TKT_price' => $ticket_price);
         //if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
         if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
             $TKT_values['TKT_ID'] = 0;
             $TKT_values['TKT_is_default'] = 0;
             $TKT_values['TKT_price'] = $ticket_price;
             $update_prices = TRUE;
         }
         //if we have a TKT_ID then we need to get that existing TKT_obj and update it
         //we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
         //keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
         if (!empty($tkt['TKT_ID'])) {
             $TKT = EE_Registry::instance()->load_model('Ticket', array($evtobj->get_timezone()))->get_one_by_ID($tkt['TKT_ID']);
             if ($TKT instanceof EE_Ticket) {
                 $ticket_sold = $TKT->count_related('Registration', array(array('STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete))))) > 0 ? true : false;
                 //let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
                 $create_new_TKT = $ticket_sold && $ticket_price != $TKT->get('TKT_price') && !$TKT->get('TKT_deleted') ? true : false;
                 $TKT->set_date_format($incoming_date_formats[0]);
                 $TKT->set_time_format($incoming_date_formats[1]);
                 //set new values
                 foreach ($TKT_values as $field => $value) {
                     if ($field == 'TKT_qty') {
                         $TKT->set_qty($value);
                     } else {
                         $TKT->set($field, $value);
                     }
                 }
                 //if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
                 if ($create_new_TKT) {
                     //archive the old ticket first
                     $TKT->set('TKT_deleted', 1);
                     $TKT->save();
                     //make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
                     $saved_tickets[$TKT->ID()] = $TKT;
                     //create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
                     $TKT = clone $TKT;
                     $TKT->set('TKT_ID', 0);
                     $TKT->set('TKT_deleted', 0);
                     $TKT->set('TKT_price', $ticket_price);
                     $TKT->set('TKT_sold', 0);
                     //now we need to make sure that $new prices are created as well and attached to new ticket.
                     $update_prices = true;
                 }
                 //make sure price is set if it hasn't been already
                 $TKT->set('TKT_price', $ticket_price);
             }
         } else {
             //no TKT_id so a new TKT
             $TKT_values['TKT_price'] = $ticket_price;
             $TKT = EE_Registry::instance()->load_class('Ticket', array($TKT_values), FALSE, FALSE);
             if ($TKT instanceof EE_Ticket) {
                 //need to reset values to properly account for the date formats
                 $TKT->set_date_format($incoming_date_formats[0]);
                 $TKT->set_time_format($incoming_date_formats[1]);
                 $TKT->set_timezone($evtobj->get_timezone());
                 //set new values
                 foreach ($TKT_values as $field => $value) {
                     if ($field == 'TKT_qty') {
                         $TKT->set_qty($value);
                     } else {
                         $TKT->set($field, $value);
                     }
                 }
                 $update_prices = TRUE;
             }
         }
         // cap ticket qty by datetime reg limits
         $TKT->set_qty(min($TKT->qty(), $TKT->qty('reg_limit')));
         //update ticket.
         $TKT->save();
         //before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
         if ($TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date')) {
             $TKT->set('TKT_end_date', $TKT->get('TKT_start_date'));
             $TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
             $TKT->save();
         }
         //initially let's add the ticket to the dtt
         $saved_dtt->_add_relation_to($TKT, 'Ticket');
         $saved_tickets[$TKT->ID()] = $TKT;
         //add prices to ticket
         $this->_add_prices_to_ticket($data['edit_prices'][$row], $TKT, $update_prices);
     }
     //however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
     $old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
     $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
     foreach ($tickets_removed as $id) {
         $id = absint($id);
         //get the ticket for this id
         $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
         //need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
         $dtts = $tkt_to_remove->get_many_related('Datetime');
         foreach ($dtts as $dtt) {
             $tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
         }
         //need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
         $tkt_to_remove->delete_related_permanently('Price');
         //finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
         $tkt_to_remove->delete_permanently();
     }
     return array($saved_dtt, $saved_tickets);
 }