/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */
package org.apache.olingo.fit.proxy.demo;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.olingo.client.api.EdmEnabledODataClient;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.ext.proxy.AbstractService;
import org.apache.olingo.ext.proxy.api.AbstractTerm;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Address;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Advertisement;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Category;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Customer;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Employee;
import org.apache.olingo.fit.proxy.demo.odatademo.types.FeaturedProduct;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Person;
import org.apache.olingo.fit.proxy.demo.odatademo.types.PersonDetail;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Product;
import org.apache.olingo.fit.proxy.demo.odatademo.types.ProductDetail;
import org.apache.olingo.fit.proxy.demo.odatademo.types.Supplier;

public class Service<C extends EdmEnabledODataClient> extends AbstractService<C> {

  // CHECKSTYLE:OFF (Maven checkstyle)
  private static final String COMPRESSED_METADATA =
      " ";
  private static final String METADATA_ETAG = null;
  // CHECKSTYLE:ON (Maven checkstyle)

  private static final Map<String, Service<?>> SERVICES = new ConcurrentHashMap<String, Service<?>>();

  @SuppressWarnings("unchecked")
  private static <C extends EdmEnabledODataClient> Service<C> getInstance(
      final ODataServiceVersion version, final String serviceRoot, final boolean transactional) {

    if (!SERVICES.containsKey(serviceRoot)) {
      final Service<C> instance = new Service<C>(COMPRESSED_METADATA, METADATA_ETAG,
          version, serviceRoot, transactional);
      SERVICES.put(serviceRoot, instance);
    }

    return (Service<C>) SERVICES.get(serviceRoot);
  }

  /**
   * Gives an OData 4.0 instance for given service root, operating in transactions (with batch requests).
   *
   * @param serviceRoot OData service root
   * @return OData 4.0 instance for given service root, operating in transactions (with batch requests)
   */
  public static Service<org.apache.olingo.client.api.EdmEnabledODataClient> getV4(
      final String serviceRoot) {

    return getV4(serviceRoot, true);
  }

  /**
   * Gives an OData 4.0 instance for given service root.
   *
   * @param serviceRoot OData service root
   * @param transactional whether operating in transactions (with batch requests) or not
   * @return OData 4.0 instance for given service root
   */
  public static Service<org.apache.olingo.client.api.EdmEnabledODataClient> getV4(
      final String serviceRoot, final boolean transactional) {

    return getInstance(ODataServiceVersion.V40, serviceRoot, transactional);
  }

  private final Map<String, Class<?>> entityTypes = new HashMap<String, Class<?>>();

  private final Map<String, Class<?>> complexTypes = new HashMap<String, Class<?>>();

  private final Map<String, Class<?>> enumTypes = new HashMap<String, Class<?>>();

  private final Map<String, Class<? extends AbstractTerm>> terms = new HashMap<String, Class<? extends AbstractTerm>>();

  public Service(final String compressedMetadata, final String metadataETag,
      final ODataServiceVersion version, final String serviceRoot, final boolean transactional) {

    super(compressedMetadata, metadataETag, version, serviceRoot, transactional);

    // CHECKSTYLE:OFF (Maven checkstyle)
    entityTypes.put("ODataDemo.Customer", Customer.class);
    entityTypes.put("ODataDemo.PersonDetail", PersonDetail.class);
    entityTypes.put("ODataDemo.ProductDetail", ProductDetail.class);
    entityTypes.put("ODataDemo.Employee", Employee.class);
    entityTypes.put("ODataDemo.Product", Product.class);
    entityTypes.put("ODataDemo.Advertisement", Advertisement.class);
    entityTypes.put("ODataDemo.Category", Category.class);
    entityTypes.put("ODataDemo.Person", Person.class);
    entityTypes.put("ODataDemo.Supplier", Supplier.class);
    entityTypes.put("ODataDemo.FeaturedProduct",
        FeaturedProduct.class);
    complexTypes.put("ODataDemo.Address", Address.class);
    // CHECKSTYLE:ON (Maven checkstyle)
  }

  @Override
  public Class<?> getEntityTypeClass(final String name) {
    return entityTypes.get(name);
  }

  @Override
  public Class<?> getComplexTypeClass(final String name) {
    return complexTypes.get(name);
  }

  @Override
  public Class<?> getEnumTypeClass(final String name) {
    return enumTypes.get(name);
  }

  @Override
  public Class<? extends AbstractTerm> getTermClass(final String name) {
    return terms.get(name);
  }

}
