/**
  * import events from CSV upload
  * @param string $filepath
  */
 protected function importEventsCSV($filepath)
 {
     global $wpdb;
     $fp = fopen($filepath, 'r');
     if ($fp === false) {
         throw new EM_ImpExpImportException('error opening CSV file');
     }
     // read first line of CSV to make sure it's the correct format -- fgetscsv is fine for this simple task!
     $header = fgetcsv($fp);
     if ($header === false) {
         throw new EM_ImpExpImportException('error reading import file or file is empty');
     }
     if (is_null($header)) {
         throw new EM_ImpExpImportException('import file handle is null');
     }
     if (!is_array($header)) {
         throw new EM_ImpExpImportException('import file did not scan as CSV');
     }
     if (!in_array('summary', $header)) {
         throw new EM_ImpExpImportException('import file does not contain a field "summary"');
     }
     $wpdb->query('start transaction');
     $records = 0;
     $rows = 0;
     $attrs = array();
     $eventCategories = self::getEventCategories();
     $eventCountries = self::getEventCountries();
     $csv = new parseCSV();
     $csv->fields = $header;
     while ($line = fgets($fp)) {
         $line = "\n{$line}\n";
         // fix up line so that it can be parsed correctly
         $cols = $csv->parse_string($line);
         if ($cols) {
             $rows++;
             $cols = $cols[0];
             // collect standard event properties
             $data = array('uid' => isset($cols['uid']) ? trim($cols['uid']) : '', 'url' => isset($cols['url']) ? self::safeURL($cols['url']) : '', 'summary' => isset($cols['summary']) ? $cols['summary'] : '', 'dtstart' => isset($cols['dtstart']) ? $cols['dtstart'] : '', 'dtend' => isset($cols['dtend']) ? $cols['dtend'] : '', 'categories' => isset($cols['categories']) ? $cols['categories'] : '', 'freq' => isset($cols['freq']) ? $cols['freq'] : '', 'byday' => isset($cols['byday']) ? $cols['byday'] : '', 'interval' => isset($cols['interval']) ? $cols['interval'] : '', 'until' => isset($cols['until']) ? $cols['until'] : '', 'post_content' => isset($cols['post_content']) ? $cols['post_content'] : '', 'post_excerpt' => isset($cols['post_excerpt']) ? $cols['post_excerpt'] : '', 'event_spaces' => isset($cols['event_spaces']) ? $cols['event_spaces'] : '', 'location_name' => isset($cols['location_name']) ? $cols['location_name'] : '', 'location_address' => isset($cols['location_address']) ? $cols['location_address'] : '', 'location_town' => isset($cols['location_town']) ? $cols['location_town'] : '', 'location_state' => isset($cols['location_state']) ? $cols['location_state'] : '', 'location_postcode' => isset($cols['location_postcode']) ? $cols['location_postcode'] : '', 'location_country' => isset($cols['location_country']) ? $cols['location_country'] : '', 'location_region' => isset($cols['location_region']) ? $cols['location_region'] : '', 'location_latitude' => isset($cols['location_latitude']) ? $cols['location_latitude'] : '', 'location_longitude' => isset($cols['location_longitude']) ? $cols['location_longitude'] : '');
             if (isset($eventCountries[strtolower($data['location_country'])])) {
                 $data['location_country'] = $eventCountries[strtolower($data['location_country'])];
             }
             // collect custom event attributes, being columns not found in standard event properties
             $attrs = array();
             foreach ($cols as $key => $value) {
                 if (strlen($value) > 0 && !isset($data[$key])) {
                     $attrs[$key] = $value;
                 }
             }
             // if we have location, try to either retrieve it by name, or create a new location object
             $location = false;
             if (self::hasLocation($data)) {
                 if ($data['location_name']) {
                     // try to find location by name
                     $location = $this->getLocationByName($data['location_name']);
                 }
                 if (!$location) {
                     // must create a new location object
                     $location = new EM_Location();
                     $location->location_name = empty($data['location_name']) ? self::fudgeLocationName($data) : $data['location_name'];
                     $location->location_address = empty($data['location_address']) ? $data['location_name'] : $data['location_address'];
                     $location->location_town = $data['location_town'];
                     $location->location_state = $data['location_state'];
                     $location->location_postcode = $data['location_postcode'];
                     $location->location_country = $data['location_country'];
                     $location->location_region = $data['location_region'];
                     $location->location_latitude = $data['location_latitude'];
                     $location->location_longitude = $data['location_longitude'];
                     self::maybeSetCoordinates($location);
                     $location->save();
                 }
             }
             // try to find existing event with matching unique ID first, so can update it
             $event = false;
             if ($data['uid']) {
                 add_filter('em_events_get_default_search', array(__CLASS__, 'filterEventArgs'), 10, 2);
                 add_filter('em_events_build_sql_conditions', array(__CLASS__, 'filterEventSQL'), 10, 2);
                 $event = EM_Events::get(array('em_impexp_uid' => $data['uid']));
                 $event = count($event) > 0 ? $event[0] : false;
                 remove_filter('em_events_get_default_search', array(__CLASS__, 'filterEventArgs'), 10, 2);
                 remove_filter('em_events_build_sql_conditions', array(__CLASS__, 'filterEventSQL'), 10, 2);
             }
             if (!$event) {
                 // must create a new event
                 $event = new EM_Event();
             }
             $event->location_id = $location ? $location->location_id : 0;
             $event->event_attributes['em_impexp_uid'] = $data['uid'];
             $event->event_attributes['em_impexp_url'] = $data['url'];
             $event->event_name = $data['summary'];
             $event->post_content = $data['post_content'];
             $event->post_excerpt = $data['post_excerpt'];
             if (preg_match('@^\\d\\d/\\d\\d/\\d\\d\\d\\d$@', $data['dtstart'])) {
                 $data['dtstart'] .= ' 00:00:00';
                 $event->start = date_create_from_format('d/m/Y H:i:s', $data['dtstart'])->getTimestamp();
                 $event->event_start_date = date('Y-m-d', $event->start);
                 $event->event_start_time = date('H:i:s', $event->start);
             }
             if (preg_match('@^\\d\\d/\\d\\d/\\d\\d\\d\\d$@', $data['dtend'])) {
                 $data['dtend'] .= ' 00:00:00';
                 $event->end = date_create_from_format('d/m/Y H:i:s', $data['dtend'])->getTimestamp();
                 $event->event_end_date = date('Y-m-d', $event->end);
                 $event->event_end_time = date('H:i:s', $event->end);
             } else {
                 $event->end = $event->start;
                 $event->event_end_date = $event->event_start_date;
                 $event->event_end_time = $event->event_start_time;
             }
             $event->event_date_modified = current_time('mysql');
             $event->event_all_day = $event->event_start_time === '00:00:00' && $event->event_end_time === '00:00:00' ? 1 : 0;
             foreach ($attrs as $attrName => $value) {
                 $event->event_attributes[$attrName] = $value;
             }
             // TODO: recurring events
             switch ($data['freq']) {
                 case 'DAILY':
                     break;
                 case 'WEEKLY':
                     //~ $event->freq = $data['freq'];
                     //~ $event->byday = $data['byday'];
                     //~ $event->interval = $data['interval'];
                     //~ $event->until = $data['until'];
                     break;
                 case 'MONTHLY':
                     break;
             }
             if ($event) {
                 $event->save();
                 $event->save_meta();
                 if ($data['categories']) {
                     $categories = explode(',', $data['categories']);
                     $eventcats = $event->get_categories();
                     foreach ($categories as $category) {
                         $category = trim($category);
                         if (isset($eventCategories[$category])) {
                             $cat = $eventCategories[$category];
                         } else {
                             $cat = wp_insert_term($category, 'event-categories');
                             if (is_array($cat)) {
                                 $cat = new EM_Category($cat['term_id']);
                                 $eventCategories[$category] = $cat;
                             }
                         }
                         if ($cat) {
                             $eventcats->categories[$cat->id] = $cat;
                         }
                     }
                     $eventcats->save();
                 }
             }
             $records++;
         }
     }
     $wpdb->query('commit');
     $this->plugin->showMessage($records === 1 ? '1 events loaded' : "{$records} events loaded");
 }