/**
 * JaDOrT: JASMINe Deployment Orchestration Tool
 * Copyright (C) 2008-2009 Bull S.A.S.
 * Copyright (C) 2008-2009 France Telecom R&D
 * Contact: jasmine@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id: DummyEntityManager.java 3200 2009-03-24 16:23:59Z alitokmen $
 * --------------------------------------------------------------------------
 */
package org.ow2.jasmine.jadort.service.implementation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import javax.persistence.TemporalType;

/**
 * Dummy EJB3 entity manager.
 * 
 * @author S. Ali Tokmen
 */
public class DummyEntityManager implements EntityManager {

    protected static int lastId = 0;

    protected static Map<Integer, Object> contents = new HashMap<Integer, Object>();

    public void clear() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public void close() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public boolean contains(final Object arg0) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public Query createNamedQuery(final String arg0) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public Query createNativeQuery(final String arg0) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    @SuppressWarnings("unchecked")
    public Query createNativeQuery(final String arg0, final Class arg1) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public Query createNativeQuery(final String arg0, final String arg1) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public Query createQuery(final String arg0) {
        return new DummyQuery(arg0);
    }

    @SuppressWarnings("unchecked")
    public <T> T find(final Class<T> arg0, final Object arg1) {
        Object result = DummyEntityManager.contents.get(arg1);
        if (result.getClass().equals(arg0)) {
            return (T) result;
        } else {
            return null;
        }
    }

    public void flush() {
        // Nothing
    }

    public Object getDelegate() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public FlushModeType getFlushMode() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public <T> T getReference(final Class<T> arg0, final Object arg1) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public EntityTransaction getTransaction() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public boolean isOpen() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public void joinTransaction() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public void lock(final Object arg0, final LockModeType arg1) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public <T> T merge(final T arg0) {
        if (arg0 == null) {
            throw new NullPointerException();
        }
        this.persist(arg0);
        return arg0;
    }

    @SuppressWarnings("unchecked")
    public void persist(final Object arg0) {
        if (arg0 == null) {
            throw new NullPointerException();
        }
        boolean present = DummyEntityManager.contents.values().contains(arg0);
        if (!present) {
            DummyEntityManager.lastId++;
            DummyEntityManager.contents.put(DummyEntityManager.lastId, arg0);
        }
        Class<?> argumentClass = arg0.getClass();
        for (Field field : argumentClass.getDeclaredFields()) {
            if (field.getName().equals("serialVersionUID")) {
                continue;
            }

            boolean set = true;
            String setter = "set" + field.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) + field.getName().substring(1);
            String getter = "get" + field.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) + field.getName().substring(1);

            annotations: for (Annotation annotation : field.getAnnotations()) {
                if (annotation.annotationType().equals(javax.persistence.Id.class)) {
                    if (!present) {
                        set = false;
                        for (Method method : arg0.getClass().getMethods()) {
                            if (method.getName().equals(setter)) {
                                try {
                                    if (field.getType().equals(int.class)) {
                                        method.invoke(arg0, DummyEntityManager.lastId);
                                    } else {
                                        method.invoke(arg0, Integer.valueOf(DummyEntityManager.lastId));
                                    }
                                    set = true;
                                    break annotations;
                                } catch (Exception e) {
                                    throw new IllegalArgumentException("Failed setting id for object \"" + arg0.toString()
                                        + "\"", e);
                                }
                            }
                        }
                    }
                } else if (annotation.annotationType().equals(javax.persistence.OneToOne.class)) {
                    set = false;
                    for (Method method : arg0.getClass().getMethods()) {
                        if (method.getName().equals(getter)) {
                            try {
                                Object o = method.invoke(arg0);
                                if (o != null) {
                                    this.persist(o);
                                }
                                set = true;
                                break annotations;
                            } catch (Exception e) {
                                throw new IllegalArgumentException("Failed persisting field \"" + field.getName()
                                    + "\" of object \"" + arg0.toString() + "\"", e);
                            }
                        }
                    }
                } else if (annotation.annotationType().equals(javax.persistence.OneToMany.class)) {
                    set = false;
                    for (Method method : arg0.getClass().getMethods()) {
                        if (method.getName().equals(getter)) {
                            try {
                                Collection c = (Collection) method.invoke(arg0);
                                if (c != null) {
                                    for (Object o : c) {
                                        this.persist(o);
                                    }
                                }
                                set = true;
                                break annotations;
                            } catch (Exception e) {
                                throw new IllegalArgumentException("Failed persisting field \"" + field.getName()
                                    + "\" of object \"" + arg0.toString() + "\"", e);
                            }
                        }
                    }
                } else if (annotation.annotationType().equals(javax.persistence.Transient.class)) {
                    set = false;
                    Object value = null;
                    for (Method method : arg0.getClass().getMethods()) {
                        if (method.getName().equals(getter)) {
                            try {
                                value = method.invoke(argumentClass.newInstance());
                                set = true;
                                break;
                            } catch (Exception e) {
                                throw new IllegalArgumentException("Failed getting default value of transient field \""
                                    + field.getName() + "\" of object \"" + arg0.toString() + "\"", e);
                            }
                        }
                    }
                    if (set) {
                        set = false;
                        for (Method method : arg0.getClass().getMethods()) {
                            if (method.getName().equals(setter)) {
                                try {
                                    method.invoke(arg0, new Object[] {value});
                                    set = true;
                                    break annotations;
                                } catch (Exception e) {
                                    throw new IllegalArgumentException("Failed nulling out transient field \""
                                        + field.getName() + "\" of object \"" + arg0.toString() + "\"", e);
                                }
                            }
                        }
                    }
                }
            }

            if (!set) {
                throw new IllegalArgumentException("No getter/setter (" + getter + "/" + setter + ") found for field \""
                    + field.getName() + "\" of object \"" + arg0.toString() + "\"");
            }
        }
    }

    public void refresh(final Object arg0) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    public void remove(final Object arg0) {
        if (arg0 == null) {
            throw new NullPointerException();
        }
        for (Map.Entry<Integer, Object> entry : DummyEntityManager.contents.entrySet()) {
            if (entry.getValue().equals(arg0)) {
                DummyEntityManager.contents.remove(entry.getKey());
                break;
            }
        }
    }

    public void setFlushMode(final FlushModeType arg0) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Auto-generated method stub");
    }

    private class DummyQuery implements Query {

        private String query;

        public DummyQuery(final String query) {
            this.query = query;
        }

        public int executeUpdate() {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        @SuppressWarnings("unchecked")
        public List getResultList() {
            List result = new ArrayList();
            for (Object o : DummyEntityManager.contents.values()) {
                if (this.query.contains(' ' + o.getClass().getSimpleName() + ' ')
                    || this.query.contains('_' + o.getClass().getSimpleName() + ' ')) {
                    result.add(o);
                }
            }
            return result;
        }

        public Object getSingleResult() {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setFirstResult(final int arg0) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setFlushMode(final FlushModeType arg0) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setHint(final String arg0, final Object arg1) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setMaxResults(final int arg0) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setParameter(final String arg0, final Object arg1) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setParameter(final int arg0, final Object arg1) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setParameter(final String arg0, final Date arg1, final TemporalType arg2) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setParameter(final String arg0, final Calendar arg1, final TemporalType arg2) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setParameter(final int arg0, final Date arg1, final TemporalType arg2) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

        public Query setParameter(final int arg0, final Calendar arg1, final TemporalType arg2) {
            // TODO Auto-generated method stub
            throw new UnsupportedOperationException("Auto-generated method stub");
        }

    }
}
