/*
 * Copyright 2002-2009 the original author or authors.
 *
 * 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.
 */
package anyframe.core.basis.dao.hibernate;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.ClassUtils;

import anyframe.common.Page;
import anyframe.common.util.SearchVO;
import anyframe.common.util.StringUtil;
import anyframe.core.basis.dao.GenericDao;
import anyframe.core.hibernate.IDynamicHibernateService;
import anyframe.core.properties.IPropertiesService;

/**
 * This class serves as the Base class for all other
 * DAOs - namely to hold common CRUD methods that they
 * might all use. You should only need to extend this
 * class when your require custom CRUD logic. <p/>
 * 
 * @author <a href="mailto:bwnoll@gmail.com">Bryan Noll</a>
 * @author modified by SooYeon Park
 * @param <T>
 *        a type variable
 * @param <PK>
 *        the primary key for that type
 */
public class GenericDaoHibernate<T, PK extends Serializable> implements
        GenericDao<T, PK> {
    /**
     * Log variable for all child classes. Uses
     * LogFactory.getLog(getClass()) from Commons
     * Logging
     */
    protected final Log log = LogFactory.getLog(getClass());
    private Class<T> persistentClass;
    private HibernateTemplate hibernateTemplate;
    private SessionFactory sessionFactory;

    /** an instance variable for the propertiesService. */
    private IPropertiesService propertiesService;

    /**
     * This dynamicHibernateService is used to get
     * dynamicHibernateService services
     */
    private IDynamicHibernateService dynamicHibernateService;

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    /**
     * Sets the propertiesService to use.
     * @param propertiesService
     *        The propertiesService to set
     */
    public void setPropertiesService(IPropertiesService propertiesService) {
        this.propertiesService = propertiesService;
    }

    /**
     * Sets the dynamicHibernateService to use.
     * @param dynamicHibernateService
     *        The dynamicHibernateService to set
     */
    public void setDynamicHibernateService(
            IDynamicHibernateService dynamicHibernateService) {
        this.dynamicHibernateService = dynamicHibernateService;
    }

    /**
     * Constructor that takes in a class to see which
     * type of entity to persist. Use this constructor
     * when subclassing.
     * @param persistentClass
     *        the class type you'd like to persist
     */
    public GenericDaoHibernate(final Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public HibernateTemplate getHibernateTemplate() {
        return this.hibernateTemplate;
    }

    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    @Autowired
    @Required
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public T get(PK id) throws Exception {
        T entity = (T) hibernateTemplate.get(this.persistentClass, id);

        if (entity == null) {
            log.warn("Uh oh, '" + this.persistentClass + "' object with id '"
                + id + "' not found...");
            throw new ObjectRetrievalFailureException(this.persistentClass, id);
        }

        return entity;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public boolean exists(PK id) throws Exception {
        T entity = (T) hibernateTemplate.get(this.persistentClass, id);
        return entity != null;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public T save(T object) throws Exception {
        return (T) hibernateTemplate.merge(object);
    }

    /**
     * {@inheritDoc}
     */
    public void remove(PK id) throws Exception {
        hibernateTemplate.delete(this.get(id));
    }

    public IPropertiesService getPropertiesService() {
        return propertiesService;
    }

    public IDynamicHibernateService getDynamicHibernateService() {
        return dynamicHibernateService;
    }

    /**
     * {@inheritDoc}
     */
    public Page getList(SearchVO searchVO) throws Exception {
        int pageIndex = searchVO.getPageIndex();
        int pageSize = this.getPropertiesService().getInt("PAGE_SIZE");
        int pageUnit = this.getPropertiesService().getInt("PAGE_UNIT");

        String searchCondition =
            StringUtil.null2str(searchVO.getSearchCondition());
        String searchKeyword = StringUtil.null2str(searchVO.getSearchKeyword());
        String isNumeric =
            StringUtil.isNumeric(searchKeyword) ? "true" : "false";

        Object[] args = new Object[4];
        args[0] = "condition=" + searchCondition;
        args[1] = "keywordStr=%" + searchKeyword + "%";
        args[2] = "keywordNum=" + searchKeyword + "";
        args[3] = "isNumeric=" + isNumeric;

        List resultList =
            this.getDynamicHibernateService()
                .findList(
                    "find" + ClassUtils.getShortName(getPersistentClass())
                        + "List", args, pageIndex, pageSize);
        Long totalSize =
            (Long) this.getDynamicHibernateService().find(
                "count" + ClassUtils.getShortName(getPersistentClass())
                    + "List", args);

        Page resultPage =
            new Page(resultList, pageIndex, totalSize.intValue(), pageUnit,
                pageSize);
        return resultPage;
    }
}

