/**
 * Perform mapping of extracted media metadata to CollectiveAccess bundles.
 *
 * @param BundlableLabelableBaseModelWithAttributes $po_instance Model instance to insert extracted metadata into
 * @param array $pa_metadata Extracted metadata
 * @param int $pn_locale_id The current locale as a numeric locale_id
 * @return bool True extracted metadata was mapped and the model changed, false if no change was made to the model
 */
function caExtractEmbeddedMetadata($po_instance, $pa_metadata, $pn_locale_id)
{
    if (!is_array($pa_metadata)) {
        return false;
    }
    $vb_did_mapping = false;
    if (!($vs_media_metadata_config = $po_instance->getAppConfig()->get('media_metadata'))) {
        return false;
    }
    $o_metadata_config = Configuration::load($vs_media_metadata_config);
    $va_mappings = $o_metadata_config->getAssoc('import_mappings');
    $vs_tablename = $po_instance->tableName();
    // set extracted georef?
    $va_georef_elements = $o_metadata_config->getList('extract_embedded_exif_georeferencing_to');
    $va_georef_containers = $o_metadata_config->getAssoc('extract_embedded_exif_georeferencing_to_container');
    $va_date_elements = $o_metadata_config->getList('extract_embedded_exif_creation_date_to');
    $va_date_containers = $o_metadata_config->getAssoc('extract_embedded_exif_creation_date_to_container');
    if (isset($pa_metadata['EXIF']) && is_array($pa_metadata['EXIF']) && (is_array($va_georef_elements) && sizeof($va_georef_elements) || is_array($va_georef_containers) && sizeof($va_georef_containers) || is_array($va_date_elements) && sizeof($va_date_elements) || is_array($va_date_containers) && sizeof($va_date_containers))) {
        $va_exif_data = $pa_metadata['EXIF'];
        if (is_array($va_georef_elements)) {
            if (is_array($va_coords = caParseEXIFLatLong($va_exif_data))) {
                foreach ($va_georef_elements as $vs_element) {
                    $va_tmp = explode('.', $vs_element);
                    $po_instance->addAttribute(array($va_tmp[1] => "[" . $va_coords['latitude'] . ", " . $va_coords['longitude'] . "]", 'locale_id' => $pn_locale_id), $va_tmp[1]);
                }
                $vb_did_mapping = true;
            }
        }
        if (is_array($va_georef_containers)) {
            if (is_array($va_coords = caParseEXIFLatLong($va_exif_data))) {
                foreach ($va_georef_containers as $vs_container => $va_info) {
                    $va_tmp = explode('.', $vs_container);
                    $vs_value_element = array_pop(explode('.', $va_info['value']));
                    $va_data = array($vs_value_element => "[" . $va_coords['latitude'] . ", " . $va_coords['longitude'] . "]", 'locale_id' => $pn_locale_id);
                    if (isset($va_info['map']) && is_array($va_info['map'])) {
                        foreach ($va_info['map'] as $vs_sub_element => $vs_value) {
                            $va_tmp2 = explode('.', $vs_sub_element);
                            $vs_sub_element = array_pop($va_tmp2);
                            if ($t_element = $po_instance->_getElementInstance($vs_sub_element)) {
                                switch ($t_element->get('datatype')) {
                                    case 3:
                                        // List
                                        $t_list = new ca_lists();
                                        $va_data[$vs_sub_element] = $t_list->getItemIDFromList($t_element->get('list_id'), $vs_value);
                                        break;
                                    default:
                                        $va_data[$vs_sub_element] = $vs_value;
                                        break;
                                }
                            }
                        }
                    }
                    $po_instance->addAttribute($va_data, $va_tmp[1]);
                }
                $vb_did_mapping = true;
            }
        }
        if (is_array($va_date_elements)) {
            if (($vs_raw_date = $va_exif_data['IFD0']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['EXIF']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['ExifIFD']['DateTimeOriginal'])) {
                $va_date_tmp = preg_split('![: ]+!', $vs_raw_date);
                $vs_date = $va_date_tmp[0] . '-' . $va_date_tmp[1] . '-' . $va_date_tmp[2] . 'T' . $va_date_tmp[3] . ':' . $va_date_tmp[4] . ':' . $va_date_tmp[5];
                foreach ($va_date_elements as $vs_element) {
                    $va_tmp = explode('.', $vs_element);
                    if (strlen($po_instance->get($vs_element)) > 0) {
                        $po_instance->addAttribute(array($va_tmp[1] => $vs_date, 'locale_id' => $pn_locale_id), $va_tmp[1]);
                    } else {
                        $po_instance->replaceAttribute(array($va_tmp[1] => $vs_date, 'locale_id' => $pn_locale_id), $va_tmp[1]);
                    }
                }
                $vb_did_mapping = true;
            }
        }
        if (is_array($va_date_containers)) {
            $t_list = new ca_lists();
            if (($vs_raw_date = $va_exif_data['IFD0']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['EXIF']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['ExifIFD']['DateTimeOriginal'])) {
                $va_date_tmp = preg_split('![: ]+!', $vs_raw_date);
                $vs_date = $va_date_tmp[0] . '-' . $va_date_tmp[1] . '-' . $va_date_tmp[2] . 'T' . $va_date_tmp[3] . ':' . $va_date_tmp[4] . ':' . $va_date_tmp[5];
                foreach ($va_date_containers as $vs_container => $va_info) {
                    $va_tmp = explode('.', $vs_container);
                    $vs_value_element = array_pop(explode('.', $va_info['value']));
                    $va_data = array($vs_value_element => $vs_date, 'locale_id' => $pn_locale_id);
                    if (isset($va_info['map']) && is_array($va_info['map'])) {
                        foreach ($va_info['map'] as $vs_sub_element => $vs_value) {
                            $va_tmp2 = explode('.', $vs_sub_element);
                            $vs_sub_element = array_pop($va_tmp2);
                            if ($t_element = $po_instance->_getElementInstance($vs_sub_element)) {
                                switch ($t_element->get('datatype')) {
                                    case 3:
                                        // List
                                        $va_data[$vs_sub_element] = $t_list->getItemIDFromList($t_element->get('list_id'), $vs_value);
                                        break;
                                    default:
                                        $va_data[$vs_sub_element] = $vs_value;
                                        break;
                                }
                            }
                        }
                    }
                    $po_instance->addAttribute($va_data, $va_tmp[1]);
                }
                $vb_did_mapping = true;
            }
        }
    }
    if (!isset($va_mappings[$po_instance->tableName()])) {
        return $vb_did_mapping;
    }
    $va_mapping = $va_mappings[$vs_tablename];
    $vs_type = $po_instance->getTypeCode();
    if (isset($va_mapping[$vs_type]) && is_array($va_mapping[$vs_type])) {
        $va_mapping = $va_mapping[$vs_type];
    } else {
        if (isset($va_mapping['__default__']) && is_array($va_mapping['__default__'])) {
            $va_mapping = $va_mapping['__default__'];
        } else {
            return $vb_did_mapping;
        }
    }
    foreach ($va_mapping as $vs_metadata => $va_attr) {
        $va_tmp = explode(":", $vs_metadata);
        $vs_delimiter = caGetOption('delimiter', $va_attr, false);
        foreach ($va_attr as $vs_attr) {
            if ($vs_attr == 'delimiter') {
                continue;
            }
            $va_metadata =& $pa_metadata;
            foreach ($va_tmp as $vs_el) {
                if (isset($va_metadata[$vs_el])) {
                    $va_metadata =& $va_metadata[$vs_el];
                } else {
                    continue 2;
                }
            }
            if (is_array($va_metadata)) {
                $va_metadata = join(";", $va_metadata);
            }
            if (!is_int($va_metadata)) {
                // pass ints through for values like WhiteBalance = 0
                if (!trim($va_metadata)) {
                    continue 2;
                }
            }
            if (!caSeemsUTF8($va_metadata)) {
                $va_metadata = caEncodeUTF8Deep($va_metadata);
            }
            $va_tmp2 = explode(".", $vs_attr);
            switch ($va_tmp2[0]) {
                case 'preferred_labels':
                    $po_instance->replaceLabel(array($va_tmp2[1] => $va_metadata), $pn_locale_id, null, true);
                    break;
                case 'nonpreferred_labels':
                    $po_instance->replaceLabel(array($va_tmp2[1] => $va_metadata), $pn_locale_id, null, false);
                    break;
                default:
                    if ($po_instance->hasField($vs_attr)) {
                        $po_instance->set($vs_attr, $va_metadata);
                    } else {
                        // try as attribute
                        if (sizeof($va_tmp2) == 2) {
                            // format ca_objects.foo, we only want "foo"
                            if ($vs_delimiter) {
                                $va_m = explode($vs_delimiter, $va_metadata);
                                $po_instance->removeAttributes($va_tmp2[1]);
                                foreach ($va_m as $vs_m) {
                                    $po_instance->addAttribute(array($va_tmp2[1] => trim($vs_m), 'locale_id' => $pn_locale_id), $va_tmp2[1]);
                                }
                            } else {
                                $po_instance->replaceAttribute(array($va_tmp2[1] => $va_metadata, 'locale_id' => $pn_locale_id), $va_tmp2[1]);
                            }
                        }
                    }
            }
            $vb_did_mapping = true;
        }
    }
    return $vb_did_mapping;
}