package brn.distsim.ormapper.class2hbm;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.collection.PersistentList;
import org.hibernate.collection.PersistentMap;
import org.hibernate.collection.PersistentSet;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.python.core.PyInstance;
import org.python.core.PyObject;
import org.python.core.PyProxy;
import org.python.core.PyStringMap;


public class PyPersister implements EntityTuplizer  {
  
  private EntityMetamodel entityMetamodel;
  private PersistentClass mappingInfo;
  private Map mapIdentifer;
  private Map mapValues;
  
  public PyPersister(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) {
    this.entityMetamodel = entityMetamodel;
    this.mappingInfo = mappingInfo;
    this.mapIdentifer = new HashMap();
    this.mapValues = new HashMap();
  }
  
  
  public Object getPropertyValue(Object entity, int i)
      throws HibernateException {
    PyProxy proxy = (PyProxy) entity;
    PyInstance pyInstance = proxy._getPyInstance();
    Object[] values = (Object[]) mapValues.get(entity);
    Object old = null;
    if (null != values)
      old = values[i];

    Iterator iter = mappingInfo.getPropertyClosureIterator();
    Property property = (Property) iter.next();
    while ( i > 0 && iter.hasNext() ) {
      property = (Property) iter.next();
      i--;
    }
    Class returnedClass = property.getType().getReturnedClass();

    Object ret = null;
    if (property.getName().equals("entity")
        || property.getName().equals("simulationId")) {
      ret = property.getGetter( mappingInfo.getMappedClass() ).getForInsert(entity, null, null);
    } else if (property.getName().equals("subclass")) {
      ret = pyInstance.instclass.__name__;
    } else {
      PyStringMap fields = (PyStringMap) pyInstance.__dict__;
      PyObject pyObj = fields.__finditem__(property.getName());

      if (null != pyObj)  {
        ret =  pyObj.__tojava__(returnedClass);
      } else {
        ret = null;
      }
      
      if (null != old && old instanceof PersistentList) {
        PersistentList coll = (PersistentList) old;
        ret = coll;
      } else if (null != old && old instanceof PersistentMap) {
        PersistentMap coll = (PersistentMap) old;
        ret = coll;
      } else if (null != old && old instanceof PersistentSet) {
        PersistentSet coll = (PersistentSet) old;
        ret = coll;
      } else if (null != old && old instanceof PersistentCollection)
        throw new RuntimeException("Not mapped :" + old.getClass().getName());
    }
    

    if (null != ret) {
      if (!returnedClass.isInstance(ret))
        throw new RuntimeException("wrong return type (expected " + 
            returnedClass.getName() + ", got " + ret.getClass().getName() + ")");
    }
    
    return ret;
  }
  
  public Object[] getPropertyValues(Object entity) throws HibernateException {
    final int span = entityMetamodel.getPropertySpan();
    final Object[] result = new Object[span];

    for ( int j = 0; j < span; j++ ) {
      result[j] = getPropertyValue(entity, j);
    }
    return result;
  }

  /*
   * (non-Javadoc)
   * @see org.hibernate.tuple.entity.EntityTuplizer#getPropertyValuesToInsert(java.lang.Object, java.util.Map, org.hibernate.engine.SessionImplementor)
   */
  public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap,
      SessionImplementor session) throws HibernateException {
    final int span = entityMetamodel.getPropertySpan();
    final Object[] result = new Object[span];

    for ( int j = 0; j < span; j++ ) {
      result[j] = getPropertyValue(entity, j);
    }
    return result;
  }
  
  public void setPropertyValues(Object entity, Object[] values)
    throws HibernateException {
    mapValues.put(entity, values);
  }

  public void setPropertyValue(Object entity, int i, Object value)
  throws HibernateException {
  //TODO Auto-generated method stub
  
  }
  
  public void setPropertyValue(Object entity, String propertyName, Object value)
  throws HibernateException {
  //TODO Auto-generated method stub
  }
  
  public Serializable getIdentifier(Object entity) throws HibernateException {
    return (Serializable) this.mapIdentifer.get(entity);
  }
  public void setIdentifier(Object entity, Serializable id)
      throws HibernateException {
    this.mapIdentifer.put(entity, id);
  }

  
  
  
  public void afterInitialize(Object entity,
      boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
    // TODO Auto-generated method stub
    
  }
  public Object createProxy(Serializable id, SessionImplementor session)
      throws HibernateException {
    // TODO Auto-generated method stub
    return null;
  }
  public Class getConcreteProxyClass() {
    // TODO Auto-generated method stub
    return null;
  }
  public Object getPropertyValue(Object entity, String propertyName)
      throws HibernateException {
    // TODO Auto-generated method stub
    return null;
  }
  public Object getVersion(Object entity) throws HibernateException {
    // TODO Auto-generated method stub
    return null;
  }
  public boolean hasProxy() {
    // TODO Auto-generated method stub
    return false;
  }
  public boolean hasUninitializedLazyProperties(Object entity) {
    // TODO Auto-generated method stub
    return false;
  }
  public Object instantiate(Serializable id) throws HibernateException {
    // TODO Auto-generated method stub
    return null;
  }
  public boolean isInstrumented() {
    // TODO Auto-generated method stub
    return false;
  }
  public boolean isLifecycleImplementor() {
    // TODO Auto-generated method stub
    return false;
  }
  public boolean isValidatableImplementor() {
    // TODO Auto-generated method stub
    return false;
  }
  public void resetIdentifier(Object entity, Serializable currentId,
      Object currentVersion) {
    // TODO Auto-generated method stub
    
  }
  public Class getMappedClass() {
    // TODO Auto-generated method stub
    return null;
  }
  public Object instantiate() throws HibernateException {
    // TODO Auto-generated method stub
    return null;
  }
  public boolean isInstance(Object object) {
    // TODO Auto-generated method stub
    return false;
  }

}