<?php

//error_reporting(E_ERROR);

date_default_timezone_set("UTC");

$localparams_tree = getenv('LocalData')."/LocalParams.xml";
$output_file      = getenv('EPNTAPData')."/amda-granules.csv";
$ddservice_wsdl   = getenv('DD_WSDL');
$amda_rest_api    = getenv('REST_API_URL');

$mapping = array(
	'granule_uid' => '@@dataset_id@@-@@granule_index@@',
        'granule_gid' => 'data',
        'obs_id' => '@@dataset_id@@',
        'dataproduct_type' => 'ts',
        'target_name' => '@@target_name@@',
        'target_class' => '@@target_class@@',
        'time_min' => '@@granule_start_time@@',
        'time_max' => '@@granule_stop_time@@',
        'time_sampling_step_min' => '@@min_sampling@@',
        'time_sampling_step_max' => '@@max_sampling@@',
        'time_exp_min' => '',
        'time_exp_max' => '',
        'spectral_range_min' => '',
        'spectral_range_max' => '',
        'spectral_sampling_step_min' => '',
        'spectral_sampling_step_max' => '',
        'spectral_resolution_min' => '',
        'spectral_resolution_max' => '',
        'c1min' => '',
        'c1max' => '',
        'c2min' => '',
        'c2max' => '',
        'c3min' => '',
        'c3max' => '',
        's_region' => '',
        'c1_resol_min' => '',
        'c1_resol_max' => '',
        'c2_resol_min' => '',
        'c2_resol_max' => '',
        'c3_resol_min' => '',
        'c3_resol_max' => '',
        'spatial_frame_type' => '',
        'incidence_min' => '',
        'incidence_max' => '',
        'emergence_min' => '',
        'emergence_max' => '',
        'phase_min' => '',
        'phase_max' => '',
        'instrument_host_name' => '@@mission_name@@',
        'instrument_name' => '@@instrument_name@@',
        'measurement_type' => '@@measurement_type@@',
        'processing_level' => '@@processing_level@@',
        'creation_date' => '@@creation_date@@',
        'modification_date' => '@@modification_date@@',
        'release_date' => '@@release_date@@',
        'service_title' => 'AMDADB',
        'access_url' => '@@amda_rest_api_entry_point@@getGranule.php?obs_id=@@dataset_id@@&start=@@granule_start_time_timestamp@@&stop=@@granule_stop_time_timestamp@@',
        'access_format' => 'application/x-cdf-istp',
        'target_region' => '@@target_region@@',
        'publisher' => 'CDPP',
        'time_scale' => 'UTC',
        'spase_resource_id' => '@@spase_resource_id@@',
        'spase_region' => '@@spase_region@@',
        'spase_measurement_type' => '@@spase_measurement_type@@',
);

function parseSampling($sampling) {
	if (empty($sampling))
		return "";
	$unit = substr($sampling, -1);
	$value = floatval(substr($sampling, 0, -1));
	switch ($unit) {
		case "S":
			return strval($value);
		case "M":
			return strval(60.*$value);
		case "H":
			return strval(3600.*$value);
		case "D":
			return strval(86400.*$value);
		default:
			echo "[WARNING] Sampling - Unknown unit: ".$sampling.PHP_EOL;
			return $sampling;
	}
}

function parseProcessingLevel($info) {
	if (strpos($info, 'L1') !== FALSE) {
		return '2';
	}
	if (strpos($info, 'L3') !== FALSE) {
		return '5';
	}
	return '3';
}

function getEpnTapMeasurementType($measurement_type, $UCDs) {
	$generic_ucd = '';
	switch ($measurement_type) {
		case 'ThermalPlasma':
			$generic_ucd = 'phys.flux';
			break;
		case 'IonComposition':
		case 'NeutralGas':
			$generic_ucd = 'phys.composition';
			break;
		case 'EnergeticParticles':
			$generic_ucd = 'phys.particle';
			break;
		case 'Waves':
		case 'Waves.Passive':
			$generic_ucd = 'em.pw';
			break;
		case 'Ephemeris':
			$generic_ucd = 'pos.ephem';
			break;
		case 'ElectricField':
			$generic_ucd = 'phys.electField';
			break;
		case 'MagneticField':
			$generic_ucd = 'phys.magField';
			break;
		case 'Spectrum':
			$generic_ucd = 'spect';
			break;
		case 'InstrumentStatus':
			$generic_ucd = 'instr';
			break;
		case 'Irradiance':
			$generic_ucd = 'phot.flux';
			break;
		case 'Radiance':
			$generic_ucd = 'phot.radiance';
			break;
		default:
			echo "[WARNING] UCD - Unknown measurement type: ".$measurement_type.PHP_EOL;
			break;
	}
	if (!empty($generic_ucd) && !in_array($generic_ucd, $UCDs))
		array_unshift($UCDs, $generic_ucd);
	return implode(';', $UCDs);
}

function timestampToJulianDay($timestamp) {
	return intval($timestamp) / 86400 + 2440587.5;
}

function timestampToISO($timestamp) {
	return date("Y-m-d\TH:i:s\Z", $timestamp);
}

function getTargetClass($spaseRegion) {
	$parts = explode(".", $spaseRegion);
	if (count($parts) < 1) {
		echo "[WARNING] Error in ObservatoryRegion definition : ".$spaseRegion.PHP_EOL;
		return "planet";
	}
	switch ($parts[0]) {
		case "Asteroid":
			return "asteroid";
		case "Comet":
			return "comet";
		case "Earth":
		case "Jupiter":
		case "Mars":
		case "Mercury":
		case "Neptune":
		case "Pluto":
		case "Saturn":
		case "Uranus":
		case "Venus":
			if ((count($parts) > 1) && !in_array($parts[1], array("Magnetosheath", "Magnetosphere", "NearSurface", "Surface"))) {
				return "satellite";
			}
			return "planet";
		case "Heliosphere":
		case "Interstellar":
			return "interplanetary_medium";
		case "Sun":
			return "star";
	}
	echo "[WARNING] Error in ObservatoryRegion definition : ".$spaseRegion.PHP_EOL;
	return "planet";
}

function getTargetName($targetClass, $spaseRegion, $missionName, $dataset_id) {
	$parts = explode(".", $spaseRegion);
	if (count($parts) < 1) {
		return "";
	}
	switch ($targetClass) {
		case "planet":
		case "satellite":
			if ((count($parts) > 1) && !in_array($parts[1], array("Magnetosheath", "Magnetosphere", "NearSurface", "Surface"))) {
				return $parts[1];
			}
			return $parts[0];
		case "star":
		case "interplanetary_medium":
			return "Sun";
		case "comet":
			switch ($missionName) {
				case "Rosetta":
					return "67P";
				case "Giotto":
					return "1P";
				case "Astronomical Objects Ephemerides":
					if ($dataset_id == "p67-orb-all")
						return "67P";
					break;
				case "ICE":
					if ($dataset_id == "ice-mag-p21")
						return "21P";
			}
			echo "[WARNING] Comet Id not defined for mission : ".$missionName.PHP_EOL;
			return "";
	}
	echo "[WARNING] Cannot retrieve target name from target class : ".$targetClass.PHP_EOL;
	return "";
}

function getTargetRegion($targetClass, $spaseRegion) {
	$parts = explode(".", $spaseRegion);
	if (count($parts) < 1) {
		return "";
	}
	switch ($targetClass) {
		case "planet":
			if (count($parts) > 1) {
				switch ($parts[1]) {
					case "Magnetosheath":
					case "Magnetosphere":
						return "planetary-magnetosphere";
					case "NearSurface":
						if (count($parts) > 2) {
							switch ($parts[2]) {
								case "Atmosphere":
									return "planetary-atmospheres";
								case "Ionosphere":
									return "planetary-ionospheres";
							}
						}
						return "planetary-atmospheres";
					case "Surface":
						return "planetary-surfaces";
				}
			}
			break;
		case "star":
		case "interplanetary_medium":
			return "solar-wind";
	}
	return "";
}

ini_set("soap.wsdl_cache_enabled", 0);
try {
	$client = new SoapClient($ddservice_wsdl, array('trace' => 1));
}
catch  (SoapFault $exception) {
	echo "[ERROR] Cannot retrieve DDService - ".$ddservice_wsdl.PHP_EOL;
	return;
}

$amda_place_holders = array(
	'amda_rest_api_entry_point' => $amda_rest_api,
);

$doc = new DOMDocument();
@$doc->load($localparams_tree);

$xpath = new DOMXpath($doc);

$output_file_handle = fopen($output_file, 'w');
fputcsv($output_file_handle, array_keys($mapping));

$dataset_nodes = $xpath->query("/dataRoot/dataCenter/mission/instrument/dataset | /dataRoot/dataCenter/mission/observatory/instrument/dataset | /dataRoot/dataCenter/mission/instrument/datasetGroup/dataset");
$datasets = array();
foreach ($dataset_nodes as $dataset_node) {
	$dataset_place_holders = array();
	//Dataset id
	$datasetId = $dataset_node->getAttribute("xml:id");
	//if ($datasetId != 'psp-het-1hr')
	//	continue;
	if (empty($datasetId)) {
		echo "[WARNING] Cannot retrieve dataset id".PHP_EOL;
		continue;
	}
	$dataset_place_holders['dataset_id'] = $datasetId;

	//Exclude dataset with group
	$to_exclude = FALSE;
	$crt_node = $dataset_node;
	while (($crt_node != NULL) && !$to_exclude) {
		if ($crt_node->nodeType == XML_ELEMENT_NODE) {
			$group = $crt_node->getAttribute("group");
			if (!empty($group)) {
				$to_exclude = TRUE;
			}
		}
		$crt_node = $crt_node->parentNode;
	}
	if ($to_exclude) {
		echo "[WARNING] Exclude dataset ".$datasetId." (group restriction)".PHP_EOL;
		continue;
	}

	$UCDs = array();
	$parameter_nodes = $dataset_node->getElementsByTagName("parameter");
	foreach ($parameter_nodes as $parameter_node) {
		$ucd = trim($parameter_node->getAttribute('ucd'));
		if (empty($ucd))
			continue;
		$ucd_list = explode(';', $ucd);
		foreach ($ucd_list as $u) {
			$u = trim($u);
			if (empty($u))
				continue;
			if (!in_array($u, $UCDs))
				$UCDs[] = $u;
		}
	}

	$dataset_place_holders['min_sampling'] = parseSampling($dataset_node->getAttribute("sampling"));
	$dataset_place_holders['max_sampling'] = parseSampling($dataset_node->getAttribute("maxSampling"));
	$dataset_place_holders['spase_resource_id'] = $dataset_node->getAttribute("spaseId");
	$dataset_place_holders['spase_measurement_type'] = $dataset_node->getAttribute("measurement_type");
	$dataset_place_holders['measurement_type'] = getEpnTapMeasurementType($dataset_place_holders['spase_measurement_type'], $UCDs);
	$dataset_place_holders['processing_level'] = parseProcessingLevel($dataset_node->getAttribute("xml:id"));
	$target = $dataset_node->getAttribute("target");
	

	$instrument_node = NULL;
	$mission_node = NULL;
	$observatory_node = NULL;
	$dataset_group_node = NULL;

	$crt_node = $dataset_node;
	while ($crt_node = $crt_node->parentNode) {
		switch ($crt_node->nodeName) {
			case 'instrument':
				$instrument_node = $crt_node;
				break;
			case 'mission':
				$mission_node = $crt_node;
				break;
			case 'observatory':
				$observatory_node = $crt_node;
				break;
			case 'datasetGroup':
				$dataset_group_node = $crt_node;
				break;
		}
	}

	if (empty($instrument_node) || empty($mission_node)) {
		echo "[ERROR] Cannot retrieve Mission or Instrument info for dataset ".$datasetId.PHP_EOL;
		continue;
	}

	$mission_name = $mission_node->getAttribute('name');
	$instrument_name = $instrument_node->getAttribute('name');
	if (empty($target)) {
		$target = $instrument_node->getAttribute('target');
		if (empty($target)) {
			if (!empty($observatory_node)) {
				$target = $observatory_node->getAttribute('target');
			}
			if (empty($target)) {
				$target = $mission_node->getAttribute('target');
			}
		}
	}
	if (empty($target)) {
		echo "[WARNING] No target defined for ".$datasetId.PHP_EOL;
	}
	$dataset_place_holders['spase_region'] = $target;
	$dataset_place_holders['target_class'] = getTargetClass($target);
	$dataset_place_holders['target_name'] = getTargetName($dataset_place_holders['target_class'], $target, $mission_name, $datasetId);
	$dataset_place_holders['target_region'] = getTargetRegion($dataset_place_holders['target_class'], $target);
	if (!empty($observatory_node)) {
		$mission_name = $observatory_node->getAttribute('name');
	}
	$dataset_place_holders['mission_name'] = utf8_encode($mission_name);
	$dataset_place_holders['instrument_name'] = preg_replace('/[^:\/\(\) \w-]/', ' ', $instrument_name);
	if ($dataset_place_holders['instrument_name'] != $instrument_name) {
		echo "=================> ".$dataset_place_holders['instrument_name'].PHP_EOL;
	}
	if (!empty($dataset_group_node)) {
		if ($dataset_place_holders['processing_level'] == 'L2') {
			$dataset_place_holders['processing_level'] = parseProcessingLevel($dataset_group_node->getAttribute("xml:id"));
		}
	}

	try {
		$prior_id = trim($dataset_node->getAttribute('PriorID'));
		if (!empty($prior_id)) {
			$vi = str_replace("-","_",$prior_id);
		}
		else {
			$vi = str_replace("-","_",$datasetId);
		}
		$res = $client->getGranules($vi);
	}
	catch  (SoapFault $exception) {
		echo "[ERROR] Cannot retrieve granules for ".$datasetId." - ".$exception->faultstring.PHP_EOL;
		continue;
	}

	if (empty($res)) {
		echo "[ERROR] No granules for  ".$datasetId.PHP_EOL;
		continue;
	}
	
	$granules = explode(PHP_EOL, $res);
	foreach ($granules as $granule) {
		$granule_info = explode(" ", $granule);
		if (empty($granule_info) || (count($granule_info) != 4)) {
			echo "[ERROR] Bad granule info in   ".$datasetId.PHP_EOL;
			continue;
		}
		$granule_place_holders['granule_index'] = str_replace(".nc", "", $granule_info[2]);
		$granule_place_holders['granule_start_time'] = timestampToJulianDay($granule_info[0]);
		$granule_place_holders['granule_stop_time']  = timestampToJulianDay($granule_info[1]);
		$granule_place_holders['modification_date']  = timestampToISO($granule_info[3]);
		$granule_place_holders['granule_start_time_timestamp'] = $granule_info[0];
		$granule_place_holders['granule_stop_time_timestamp']  = $granule_info[1];
		$granule_place_holders['creation_date']      = $granule_place_holders['modification_date'];
		$granule_place_holders['release_date']       = $granule_place_holders['modification_date'];

		$fields = array_values($mapping);
		$all_place_holders = $amda_place_holders + $dataset_place_holders + $granule_place_holders;
		foreach ($all_place_holders as $place_holder => $value) {
			foreach ($fields as &$field) {
				$field = str_replace('@@'.$place_holder.'@@', $value, $field);
			}
		}
		fputcsv($output_file_handle, $fields);
	}
}	

fclose($output_file_handle);
?>