package com.fp.general.keygen;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.type.Type;

import com.fp.common.helper.BeanManager;
import com.fp.general.helper.PropertiesHelper;
import com.fp.persistence.commondb.PersistenceHelper;

public class SubSequenceKey extends AbstractKeyGen implements IdentifierGenerator, Configurable {
    public static final String SQL = "sql";

    public static final String TYPE = "type";

    public static final String PARAM = "param";

    public static final String FIELD = "field";

    private String sql = null;

    private String field = null;

    private Class<?> type = null;

    private final List<Map<String, String>> param = new ArrayList<Map<String, String>>();

    @Override
    public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
        try {
            EntityManager em = PersistenceHelper.getEntityManager();
            em.flush();
            Query q = em.createNativeQuery(this.sql);
            for (Map<String, String> p : this.param) {
                q.setParameter(p.get("NAME"), BeanManager.getBeanAttributeValue(object, p.get("FIELD")));
            }
            Object pk = BeanManager.getBeanAttributeValue(object, "pk");
            Object val = BeanManager.convertObject(q.getSingleResult(), this.type);
            BeanManager.setBeanAttributeValue(pk, this.field, val);
            return (Serializable) pk;
        } catch (Exception e) {
            throw new HibernateException(e);
        }
    }

    @Override
    public void configure(Type pType, Properties pParams, Dialect pD) throws MappingException {
        this.sql = PropertiesHelper.getString(SubSequenceKey.SQL, pParams, null).toUpperCase();
        this.field = PropertiesHelper.getString(SubSequenceKey.FIELD, pParams, null);
        try {
            this.type = Class.forName(PropertiesHelper.getString(SubSequenceKey.TYPE, pParams, null));
        } catch (ClassNotFoundException e) {
            throw new MappingException(e);
        }
        try {
            String sParam = PropertiesHelper.getString(SubSequenceKey.PARAM, pParams, null);
            if (sParam != null) {
                String[] aParam = sParam.split(";");
                for (String val : aParam) {
                    String[] aVal = val.split(",");
                    Map<String, String> m = new HashMap<String, String>();
                    m.put("NAME", aVal[0].toUpperCase());
                    m.put("FIELD", aVal[1]);
                    this.param.add(m);
                }
            }
        } catch (Exception e) {
            throw new MappingException(e);
        }
    }

}