package com.acme.model.domain.ad.sessionbean;


import com.acme.model.domain.ad.dao.ADDao;
import com.acme.model.domain.ad.entity.Branch;
import com.acme.model.domain.ad.entity.City;
import com.acme.model.domain.ad.entity.Company;
import com.acme.model.domain.ad.entity.Country;
import com.acme.model.domain.ad.entity.Currency;
import com.acme.model.domain.ad.entity.Department;
import com.acme.model.domain.ad.entity.Employee;
import com.acme.model.domain.ad.entity.Unit;
import com.acme.model.domain.ad.entity.UnitGroup;
import com.acme.structure.BaseFilter;
import com.acme.structure.GridData;
import com.acme.structure.PerformanceMonitor;
import com.acme.structure.ProfileInterceptor;
import com.acme.structure.ServerResponse;
import com.acme.structure.dao.MainDao;
import com.acme.structure.exception.persistent.RemovedEntityException;

import java.util.Collection;
import java.util.Iterator;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;

import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

import javax.interceptor.Interceptors;

import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.PersistenceContext;

import org.apache.log4j.Logger;


@Stateless(name = "ADManager", mappedName = "ejb/ADManager/remote")
@TransactionManagement(TransactionManagementType.CONTAINER)
@Interceptors(value = { PerformanceMonitor.class, ProfileInterceptor.class })
@Remote(ADManager.class)
public class ADManagerBean implements ADManager, ADManagerLocal
{
    @PersistenceContext(unitName = "restmatic")
    private EntityManager manager;

    @Resource
    SessionContext ctx;

    private Logger logger = Logger.getLogger(this.getClass());

    MainDao dao = null;
    ADDao adDao = null;

    @PostConstruct
    public void initialized()
    {
        dao = new MainDao();
        adDao = new ADDao();

        dao.setEJBContext(ctx);
    }

    @RolesAllowed( { "std", "sys" })
    public Collection findCountryGroups(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return dao.findByFilter(manager, baseFilter);
    }

    //@RolesAllowed( { "std", "sys" })

    public Collection findCountries()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection entities = dao.getEntityList(manager, new Country());
        initiateCountries(entities);

        return entities;
    }

    @RolesAllowed( { "std", "sys" })
    public Collection findCountries(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return dao.findByFilter(manager, baseFilter);
    }

    //@RolesAllowed( { "sys" })

    public ServerResponse synchronizeCountries(GridData gridData) throws Exception
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        ServerResponse response = null;

        try
        {
            response = dao.synchronizeEntities(manager, gridData, false);
            initiateCountries(response.getReturnData());
        }
        catch (Exception exc)
        {
            ctx.setRollbackOnly();
            throw exc;
        }

        return response;

    }

    @RolesAllowed( { "std", "sys" })
    public Company findCompany(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Company company = (Company)dao.findObjectByFilter(manager, baseFilter);
        company.initialize(2);

        return company;
    }

    //@RolesAllowed( { "sys" })

    public ServerResponse synchronizeCompanies(GridData gridData) throws Exception
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        ServerResponse response = null;

        try
        {
            response = dao.synchronizeEntities(manager, gridData, false);
            initiateCompanies(response.getReturnData());
        }
        catch (Exception exc)
        {
            ctx.setRollbackOnly();
            throw exc;
        }

        return response;
    }

    private void initiateCompanies(Collection dataObjects)
    {
        Iterator itr = dataObjects.iterator();
        Company company = null;
        while (itr.hasNext())
        {
            company = (Company)itr.next();
            company.initialize(2);
        }
    }

    @RolesAllowed( { "std", "sys" })
    public Collection findDepartmentsForBranch(Branch branch)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        branch = (Branch)dao.findByPrimaryKey(manager, branch);
        dao.initializeCollection(branch.getDepartments());
        return branch.getDepartments();
    }

    @RolesAllowed( { "std", "sys" })
    public Collection findUnits()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return dao.getEntityList(manager, new Unit());
    }

    @RolesAllowed( { "std", "sys" })
    public Unit findUnit(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return (Unit)dao.findObjectByFilter(manager, baseFilter);
    }

    //@RolesAllowed( { "std", "sys" })

    public Collection findUnitGroups()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection unitGroups = dao.getEntityList(manager, new UnitGroup());
        initiateUnitGroups(unitGroups);
        return unitGroups;
    }

    @RolesAllowed( { "std", "sys" })
    public Collection findUnitGroups(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection unitGroups = dao.findByFilter(manager, baseFilter);
        initiateUnitGroups(unitGroups);
        return unitGroups;
    }

    //@RolesAllowed( { "sys" })

    public ServerResponse synchronizeUnitGroups(GridData gridData) throws Exception
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        ServerResponse response = null;

        try
        {
            response = dao.synchronizeEntities(manager, gridData, false);
            initiateUnitGroups(response.getReturnData());
        }
        catch (Exception exc)
        {
            ctx.setRollbackOnly();
            throw exc;
        }

        return response;
    }

    private void initiateUnitGroups(Collection unitGroups)
    {
        Iterator itr = unitGroups.iterator();
        UnitGroup unitGroup = null;
        while (itr.hasNext())
        {
            unitGroup = (UnitGroup)itr.next();
            dao.initializeCollection(unitGroup.getUnits());
        }
    }

    @RolesAllowed( { "std", "sys" })
    public Collection findEmployee(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection employees = dao.findByFilter(manager, baseFilter);
        initiateEmployees(employees);
        return employees;
    }

    //@RolesAllowed( { "std", "sys" })

    public Collection findEmployees()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection employees = dao.getEntityList(manager, new Employee());
        initiateEmployees(employees);
        return employees;
    }

    //@RolesAllowed( { "sys" })

    public ServerResponse synchronizeEmployees(GridData gridData) throws Exception
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        ServerResponse response = null;

        try
        {
            response = dao.synchronizeEntities(manager, gridData, false);
            initiateEmployees(response.getReturnData());
        }
        catch (Exception exc)
        {
            ctx.setRollbackOnly();
            throw exc;
        }

        return response;
    }

    private void initiateEmployees(Collection employees)
    {
        Iterator itr = employees.iterator();
        Employee employee = null;

        while (itr.hasNext())
        {
            employee = (Employee)itr.next();
            if (employee.getUser() != null)
            {
                dao.initializeCollection(employee.getUser().getUserRoleGroups());
            }
        }
    }

    //@RolesAllowed( { "std", "sys" })

    public Collection findCurrencies()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return dao.getEntityList(manager, new Currency());
    }

    @RolesAllowed( { "std", "sys" })
    public Currency findCurrency(BaseFilter baseFilter)
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return (Currency)dao.findObjectByFilter(manager, baseFilter);
    }

    //@RolesAllowed( { "sys" })

    public ServerResponse synchronizeCurrencies(GridData gridData) throws Exception
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        ServerResponse response = null;

        try
        {
            response = dao.synchronizeEntities(manager, gridData, false);
        }
        catch (Exception exc)
        {
            ctx.setRollbackOnly();
            throw exc;
        }

        return response;
    }

//    public Collection findBranchsForList()
//    {
//        manager.setFlushMode(FlushModeType.COMMIT);
//        Collection dataObjects = adDao.findBranchsForList(manager);
//        initiateBranchs(dataObjects);
//        return dataObjects;
//    }

    public Collection findBranchs()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection dataObjects = dao.getEntityList(manager, new Branch());
        initiateBranchs(dataObjects);
        return dataObjects;
    }

    private void initiateBranchs(Collection dataObjects)
    {
        Iterator itr = dataObjects.iterator();
        Branch branch = null;
        while (itr.hasNext())
        {
            branch = (Branch)itr.next();
            branch.initialize(2);
        }
    }

    public Collection findDepartments()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return dao.getEntityList(manager, new Department());
    }

    //@RolesAllowed( { "sys", "sysmgr" })

    public ServerResponse synchronizeDepartments(GridData gridData) throws Exception
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        ServerResponse response = null;

        try
        {
            response = dao.synchronizeEntities(manager, gridData, false);
        }
        catch (Exception exc)
        {
            ctx.setRollbackOnly();
            throw exc;
        }

        return response;
    }

    public Collection findDepartmentsForList()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return adDao.findDepartmentsForList(manager);
    }

    public Collection findCitiesForCountryList(Country country) throws RemovedEntityException
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        country = (Country)dao.refreshEntity(manager, country);
        dao.initializeCollection(country.getCities());
        return country.getCities();
    }

    public Collection findCitiesForList()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return adDao.findCitiesForList(manager);
    }

    public Collection findDistrictsForCityList(City city) throws RemovedEntityException
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        city = (City)dao.refreshEntity(manager, city);
        dao.initializeCollection(city.getDistricts());
        return city.getDistricts();
    }

    public Collection findDistrictsForList()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return adDao.findDistrictsForList(manager);
    }

    public Collection findUnitGroupsForList()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return adDao.findUnitGroupsForList(manager);
    }

    public Collection findCompanies()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        Collection entities = dao.getEntityList(manager, new Company());
        initiateCompanies(entities);
        return entities;
    }

    private void initiateCountries(Collection countries)
    {
        Iterator itr = countries.iterator();
        Country country = null;

        while (itr.hasNext())
        {
            country = (Country)itr.next();
            country.initialize(2);
        }
    }

    public Collection findCurrenciesForList()
    {
        manager.setFlushMode(FlushModeType.COMMIT);
        return adDao.findCurrenciesForList(manager);
    }
}
