/************************************************
 * Copyright (c) Shen Li. All rights reserved.  *
 * http://joyaop.sourceforge.net                *
 * -------------------------------------------- *
 * Distributable under LGPL license.            *
 * See terms of license at gnu.org.             *
 ************************************************/
package net.sf.joyaop.demo.rbac;

import net.sf.joyaop.ObjectFactory;
import net.sf.joyaop.config.XmlConfiguration;
import net.sf.joyaop.demo.rbac.model.*;
import net.sf.joyaop.extension.picocontainer.AspectizedComponentAdapterFactory;
import net.sf.joyaop.extension.picocontainer.PicoAspectFactory;
import net.sf.joyaop.framework.AspectRuntime;
import net.sf.joyaop.impl.AspectRuntimeImpl;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.defaults.DefaultPicoContainer;

/**
 * @author Shen Li
 */
public class Main {
    private static EntityHome entityHome;

    public static void main(String[] args) throws Throwable {
        AspectRuntime aspectRuntime = new AspectRuntimeImpl(new XmlConfiguration("net/sf/joyaop/demo/rbac/aop.xml"));
        MutablePicoContainer container = new DefaultPicoContainer(
                new AspectizedComponentAdapterFactory(aspectRuntime));
        aspectRuntime.setAspectFactory(new PicoAspectFactory(container));

        container.registerComponentInstance(ObjectFactory.class, aspectRuntime);
        container.registerComponentImplementation(SessionManager.class);
        container.registerComponentImplementation(EntityHome.class, EntityHomeImpl.class);
        container.registerComponentImplementation(Context.class, ContextImpl.class);
        container.registerComponentImplementation(AuthenticationManager.class, AuthenticationManagerImpl.class);
        container.registerComponentImplementation(Facade.class);

        SessionManager sessionManager = (SessionManager) container.getComponentInstance(SessionManager.class);
        ContextImpl context = (ContextImpl) container.getComponentInstance(Context.class);
        Facade facade = (Facade) container.getComponentInstance(Facade.class);
        entityHome = (EntityHome) container.getComponentInstance(EntityHome.class);

//        SimpleAspectFactory aspectFactory = new SimpleAspectFactory();
//
//        Interceptor interceptor = new JoyInterceptor(aspectRuntime);
//        SessionManager sessionManager = new SessionManager(interceptor);
//
//        entityHome = (EntityHome) aspectRuntime.newInstance(
//                EntityHomeImpl.class,
//                new Class[] { ObjectFactory.class, SessionManager.class },
//                new Object[] { aspectRuntime, sessionManager });

//        aspectFactory.addAspect(
//                SessionInterceptor.class,
//                new Class[] { SessionManager.class },
//                new Object[] { sessionManager });

//        ContextImpl context = new ContextImpl(entityHome);
//
//        AuthenticationManager authenticationManager = (AuthenticationManager) aspectRuntime.newInstance(
//                AuthenticationManagerImpl.class,
//                new Class[] { EntityHome.class, Context.class },
//                new Object[] { entityHome, context });
//
//        aspectFactory.addAspect(
//                AuthenticationInterceptor.class,
//                new Class[] { AuthenticationManager.class },
//                new Object[] { authenticationManager });

        Session session = null;
        Transaction tx = null;
        try {
            session = sessionManager.openSession();
            tx = session.beginTransaction();

            Permission root = createPermission("root", "Root of all the other permissions", null);
            Permission create = createPermission("create", "create a new one", root);
            Permission delete = createPermission("delete", "delete an exsisting one", root);

            Role admin = createRole("admin", "administrator", root);
            Role user = createRole("user", "user", delete);

            Group adminGroup = createGroup("admin", "administrator group", admin);
            Group userGroup = createGroup("user", "user group", user);

            User shenli = createUser("shenli", "password", "theshenli@hotmail.com", "student", adminGroup);
            User john = createUser("john", "password", "john@foo.com", "student", userGroup);

            session.flush();

            invokeFacadeMethod(shenli, context, facade);
            invokeFacadeMethod(john, context, facade);
            tx.commit();
        } catch (Throwable t) {
            if (tx != null) {
                tx.rollback();
            }
            throw t;
        } finally {
            sessionManager.closeSession();
        }
    }

    private static void invokeFacadeMethod(Principle principle, ContextImpl context, Facade facade) {
        System.out.println();
        System.out.println("Principle " + principle.getName() + " invoke methods...");
        context.setCurrentPrinciple(principle);
        try {
            facade.create();
        } catch (AccessDeniedException e) {
            System.out.println(
                    "****** Principle " + principle.getName()
                    + " has no permission to invoke method create ******");
        }
        try {
            facade.delete();
        } catch (AccessDeniedException e) {
            System.out.println(
                    "****** Principle " + principle.getName()
                    + " has no permission to invoke method delete ******");
        }
    }

    private static User createUser(String name, String password, String email, String description, Group group) {
        System.out.println();
        System.out.println("Creating user...");
        User user = (User) entityHome.newEntity(User.class);
        user.setName(name);
        user.setEmail(email);
        user.addParent(group);
        group.addChild(user);
        user.setPassword(password);
        user.setDescription(description);
        entityHome.saveEntity(user);
        System.out.println("id: " + user.getId());
        System.out.println("name: " + user.getName());
        System.out.println("description: " + user.getDescription());
        System.out.println("email: " + user.getEmail());
        System.out.println("password: " + user.getPassword());
        System.out.println("group: " + ((Group) user.getParents().iterator().next()).getName());
        return user;
    }

    private static Group createGroup(String name, String description, Role role) {
        System.out.println();
        System.out.println("Creating group...");
        Group group = (Group) entityHome.newEntity(Group.class);
        group.setName(name);
        group.setDescription(description);
        group.addRole(role);
        entityHome.saveEntity(group);
        System.out.println("id: " + group.getId());
        System.out.println("name: " + group.getName());
        System.out.println("description: " + group.getDescription());
        System.out.println("role: " + ((Role) group.getRoles().iterator().next()).getName());
        return group;
    }

    private static Permission createPermission(String name, String description, Permission parent) {
        System.out.println();
        System.out.println("Creating permission...");
        Permission permission = (Permission) entityHome.newEntity(Permission.class);
        permission.setName(name);
        permission.setDescription(description);
        permission.addParent(parent);
        if (parent != null) {
            parent.addChild(permission);
        }
        entityHome.saveEntity(permission);
        System.out.println("id: " + permission.getId());
        System.out.println("name: " + permission.getName());
        System.out.println("description: " + permission.getDescription());
        System.out.println("parent permission: "
                + ((parent == null) ? "no parent" : ((Permission) permission.getParents().iterator().next()).getName()));
        return permission;
    }

    private static Role createRole(String name, String description, Permission permission) {
        System.out.println();
        System.out.println("Creating role...");
        Role role = (Role) entityHome.newEntity(Role.class);
        role.setName(name);
        role.setDescription(description);
        role.addPermission(permission);
        entityHome.saveEntity(role);
        System.out.println("id: " + role.getId());
        System.out.println("name: " + role.getName());
        System.out.println("description: " + role.getDescription());
        System.out.println("permission: " + ((Permission) (role.getPermissions().iterator().next())).getName());
        return role;
    }

//    private static class SimpleAspectFactory extends DefaultAspectFactory {
//        private final Map aspects = new HashMap();
//
//        public Object newInstance(Class clazz) {
//            ConstructionInfo info = (ConstructionInfo) aspects.get(clazz);
//            if (info != null) {
//                return super.newInstance(clazz, info.getArgumentTypes(), info.getArguments());
//            }
//            return super.newInstance(clazz);
//        }
//
//        public void addAspect(Class implementationClass, Class[] argTypes, Object[] args) {
//            aspects.put(implementationClass, new ConstructionInfo(argTypes, args));
//        }
//
//        private static class ConstructionInfo {
//            private Class[] argumentTypes;
//            private Object[] arguments;
//
//            public ConstructionInfo(Class[] argumentTypes, Object[] arguments) {
//                this.argumentTypes = argumentTypes;
//                this.arguments = arguments;
//            }
//
//            public Class[] getArgumentTypes() {
//                return argumentTypes;
//            }
//
//            public Object[] getArguments() {
//                return arguments;
//            }
//        }
//    }
} 