package org.apache.hadoop.metadata.bridge;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import org.apache.hadoop.metadata.ITypedReferenceableInstance;
import org.apache.hadoop.metadata.MetadataException;
import org.apache.hadoop.metadata.repository.MetadataRepository;
import org.apache.hadoop.metadata.storage.RepositoryException;
import org.apache.hadoop.metadata.types.AttributeDefinition;
import org.apache.hadoop.metadata.types.ClassType;
import org.apache.hadoop.metadata.types.HierarchicalTypeDefinition;
import org.apache.hadoop.metadata.types.Multiplicity;
import org.apache.hadoop.metadata.types.TypeSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableList;

public abstract class ABridge implements IBridge {

	
	protected ArrayList<Class<? extends AEnitityBean>> typeBeanClasses = new ArrayList<Class<? extends AEnitityBean>>();
	MetadataRepository repo;
	
	protected static final Logger LOG = LoggerFactory.getLogger("BridgeLogger");
	protected HierarchicalTypeDefinition<ClassType> createClassTypeDef(String name, ImmutableList<String> superTypes, AttributeDefinition... attrDefs) {return new HierarchicalTypeDefinition(ClassType.class, name, superTypes, attrDefs);}
	
	public ArrayList<Class<? extends AEnitityBean>> getTypeBeanClasses() {
		return typeBeanClasses;
	}
	
	@Inject
	protected ABridge(MetadataRepository repo) {
	                  this.repo = repo;
	  }

	public <t extends AEnitityBean>Object get(String id) throws RepositoryException {
		// get from the system by id (?)
		ITypedReferenceableInstance ref = repo.getEntityDefinition(id);
		// turn into a HiveLineageBean
		try {
			Class<AEnitityBean> c = getTypeBeanInListByName(ref.getTypeName());
			return c.newInstance().convertFromITypedReferenceable(ref);
		} catch (BridgeException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return null;
	}

	public String create(AEnitityBean bean) throws MetadataException {

		ClassType type = TypeSystem.getInstance().getDataType(ClassType.class, bean.getClass().getSimpleName());
        ITypedReferenceableInstance refBean = null;
		try {
			refBean = type.convert(bean.convertToReferencable(), Multiplicity.REQUIRED);
			String id = repo.createEntity(refBean, type.getName());
			return id;
		} catch (IllegalArgumentException | IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		throw new MetadataException("Cannot create entity");
		
	}

	public Iterable<String> list() throws RepositoryException {
          List<String> returnList = null;
		for(Class c : typeBeanClasses){
        	  List<String> inBetweenList = repo.getEntityList(c.getSimpleName());
        	  try{returnList.addAll(inBetweenList);}
        	  catch(NullPointerException e){returnList = inBetweenList;}
          }
          return returnList;
	}

	protected final boolean containsType(String s){
		for (Class c: typeBeanClasses){
			if (c.getSimpleName().equals(s)){
				return true;
			}
		}
		return false;
	}
	
	protected final Class<AEnitityBean> getTypeBeanInListByName(String s) throws BridgeException{
		if (containsType(s)){
			for (Class c: typeBeanClasses){
				if (c.getSimpleName().equals(s)){
					return c;
				}
			}
		}else{
		throw new BridgeException("No EntityBean Definition Found");
		}
		throw new BridgeException("No EntityBean Definition Found");
	}


}
