/*
 * Copyright Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags and
 * the COPYRIGHT.txt file distributed with this work.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modified by
 * @author  Data Virtuality GmbH
 * @date    $Date$
 *
 */
package org.teiid.metadata.odata;

import java.util.HashMap;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;
import org.teiid.core.types.*;
import org.teiid.core.util.StringUtil;
import org.teiid.metadata.BaseColumn;

public class ODataType {

	private static HashMap<String, String> odataTypes = new HashMap<String, String>();
	private static HashMap<String, String> teiidTypes = new HashMap<String, String>();

	static {
		odataTypes.put("Edm.String", DataTypeManager.DefaultDataTypes.STRING);
		odataTypes.put("Edm.Boolean", DataTypeManager.DefaultDataTypes.BOOLEAN);
		odataTypes.put("Edm.Byte", DataTypeManager.DefaultDataTypes.SHORT);
		odataTypes.put("Edm.SByte", DataTypeManager.DefaultDataTypes.BYTE);
		odataTypes.put("Edm.Int16", DataTypeManager.DefaultDataTypes.SHORT);
		odataTypes.put("Edm.Int32", DataTypeManager.DefaultDataTypes.INTEGER);
		odataTypes.put("Edm.Int64", DataTypeManager.DefaultDataTypes.LONG);
		odataTypes.put("Edm.Single", DataTypeManager.DefaultDataTypes.FLOAT);
		odataTypes.put("Edm.Double", DataTypeManager.DefaultDataTypes.DOUBLE);
		odataTypes.put("Edm.Decimal", DataTypeManager.DefaultDataTypes.BIG_DECIMAL);
		odataTypes.put("Edm.Date", DataTypeManager.DefaultDataTypes.DATE);
		odataTypes.put("Edm.TimeOfDay", DataTypeManager.DefaultDataTypes.TIME);
		odataTypes.put("Edm.DateTimeOffset", DataTypeManager.DefaultDataTypes.TIMESTAMP);
		odataTypes.put("Edm.Stream", DataTypeManager.DefaultDataTypes.BLOB);
		odataTypes.put("Edm.Guid", DataTypeManager.DefaultDataTypes.STRING);
		odataTypes.put("Edm.Binary", DataTypeManager.DefaultDataTypes.VARBINARY); //$NON-NLS-1$
		odataTypes.put("Edm.Geometry", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryPoint", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryLineString", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryPolygon", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryMultiPolygon", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryMultiPoint", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryMultiLineString", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeometryCollection", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.Geography", DataTypeManager.DefaultDataTypes.GEOMETRY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyPoint", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyLineString", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyPolygon", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyMultiPolygon", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyMultiPoint", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyMultiLineString", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		odataTypes.put("Edm.GeographyCollection", DataTypeManager.DefaultDataTypes.GEOGRAPHY); //$NON-NLS-1$
		teiidTypes.put(DataTypeManager.DefaultDataTypes.STRING, "Edm.String");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.BOOLEAN, "Edm.Boolean");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.BYTE, "Edm.SByte");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.SHORT, "Edm.Int16");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.INTEGER, "Edm.Int32");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.LONG, "Edm.Int64");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.FLOAT, "Edm.Single");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.DOUBLE, "Edm.Double");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.BIG_INTEGER, "Edm.Decimal");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.BIG_DECIMAL, "Edm.Decimal");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.DATE, "Edm.Date");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.TIME, "Edm.TimeOfDay");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.TIMESTAMP, "Edm.DateTimeOffset");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.BLOB, "Edm.Stream");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.CLOB, "Edm.Stream");
		//teiidTypes.put(DataTypeManager.DefaultDataTypes.JSON, "Edm.Stream");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.XML, "Edm.Stream");
		teiidTypes.put(DataTypeManager.DefaultDataTypes.VARBINARY, "Edm.Binary"); //$NON-NLS-1$
		//will fail for most values
		teiidTypes.put(DataTypeManager.DefaultDataTypes.OBJECT, "Edm.Binary"); //$NON-NLS-1$
		teiidTypes.put(DataTypeManager.DefaultDataTypes.GEOMETRY, "Edm.Stream"); //$NON-NLS-1$
		teiidTypes.put(DataTypeManager.DefaultDataTypes.GEOGRAPHY, "Edm.Stream"); //$NON-NLS-1$
	}

	public static String teiidType(SingletonPrimitiveType odataType, boolean array) {
		String type =  odataType.getFullQualifiedName().getFullQualifiedNameAsString();
		return teiidType(type, array);
	}

	public static String teiidType(String odataType, boolean array) {
		String type =  odataTypes.get(odataType);
		if (type == null) {
			type = DataTypeManager.DefaultDataTypes.STRING; // special case for enum type
		}
		if (array) {
			type +="[]";
		}
		return type;
	}

	public static boolean isEnum(String odataType) {
		return odataTypes.get(odataType) == null;
	}

	public static EdmPrimitiveTypeKind odataType(BaseColumn c) {
		String runtimeType = c.getRuntimeType();
		//try to map to the specific type
		if (c.getDatatype() != null
				&& (c.getDatatype().getName().equalsIgnoreCase(DataTypeManager.DefaultDataTypes.GEOMETRY)
				|| c.getDatatype().getName().equalsIgnoreCase(DataTypeManager.DefaultDataTypes.GEOGRAPHY))) {
			boolean geometry = c.getDatatype().getName().equalsIgnoreCase(DataTypeManager.DefaultDataTypes.GEOMETRY);
			String type = c.getProperty(BaseColumn.SPATIAL_TYPE, false);
			if (type != null) {
				try {
					return StringUtil.caseInsensitiveValueOf(EdmPrimitiveTypeKind.class,
							(geometry?"Geometry":"Geography")+type); //$NON-NLS-1$ //$NON-NLS-2$
				} catch (IllegalArgumentException e) {

				}
			}
			//unknown or null case
			if (geometry) {
				return EdmPrimitiveTypeKind.Geometry;
			}
			return EdmPrimitiveTypeKind.Geography;
		}
		return odataType(runtimeType);
	}

	public static EdmPrimitiveTypeKind odataType(String teiidRuntimeType) {
		return EdmPrimitiveTypeKind.valueOfFQN(odataTypeStr(teiidRuntimeType));
	}

	public static String odataTypeStr(String teiidRuntimeType) {
		if (teiidRuntimeType.endsWith("[]")) {
			teiidRuntimeType = teiidRuntimeType.substring(0, teiidRuntimeType.length()-2);
			//multi-dimensional is not supported - will be returned as string
		}
		String type =  teiidTypes.get(teiidRuntimeType);
		if (type == null) {
			type = "Edm.String";
		}

		return type;
	}

}
