//Copyright  2014 Oracle and/or its affiliates. All rights reserved.

import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.ArrayList;
import java.util.GregorianCalendar;

import maf.code.corner.hr.mobile.entities.DepartmentsEntity;
import maf.code.corner.hr.mobile.entities.EmployeesEntity;

import maf.code.corner.hr.mobile.json.helper.EmployeesEntityToJson;
import maf.code.corner.hr.mobile.json.helper.JsonArrayToDepartmentsArray;
import maf.code.corner.hr.mobile.json.helper.JsonArrayToEmployeesArray;
import maf.code.corner.hr.mobile.uri.DeptEmpURIs;

import maf.code.corner.hr.mobile.util.RestCallerUtil;

import oracle.adfmf.java.beans.ProviderChangeListener;
import oracle.adfmf.java.beans.ProviderChangeSupport;


public class DeptEmpDC {
    
   
   
    //allEmployees for a selected department. 
    private EmployeesEntity[] allEmployees = null;
    
    //all departments. We fecth the departments only once as this is not expected to
    //change in the context of the tutorial
    private DepartmentsEntity[] allDepartments = null;

    //collection with single employee record to edit in a MAF form. Providing a separate collection for 
    //the selected employee allows implementation of a cancel-form strategy, which is that the collection
    //data - and this the REST service - is only updated in case of a submit. If the user presses cancel 
    //then nothing happens and the navigation returns to the calling page. 
    private EmployeesEntity[] editableEmployee = new EmployeesEntity[0]; 
         
    public DeptEmpDC() {
        super();
    }
    
    public void setAllDepartments(DepartmentsEntity[] allDepartments) {}

    public DepartmentsEntity[] getAllDepartments() {
        
        if(allDepartments == null){
           
            String restURI = DeptEmpURIs.GetAllDepartmentsURI();
            RestCallerUtil rcu = new RestCallerUtil();
            String jsonArrayAsString = rcu.invokeREAD(restURI);
            DepartmentsEntity[] departments = JsonArrayToDepartmentsArray.getDepartmentsArray(jsonArrayAsString);
            allDepartments = departments;
        }
        
        return allDepartments;
    }

    public void setAllEmployees(EmployeesEntity[] allEmployees) {}

    public EmployeesEntity[] getAllEmployees() {
        
        if (allEmployees == null){
          //return empty list
            return new EmployeesEntity[0];
        }   
        
        return allEmployees;
    }

    //query the REST service for employees in a specific department and call provider refresh to 
    //refresh the allEmployees collection. 
    public void prepareEmployeesForDepartment(Integer departmentId){
        
        String restURI = DeptEmpURIs.GetEmployeesinDept(departmentId);
        RestCallerUtil rcu = new RestCallerUtil();
        String jsonArrayAsString = rcu.invokeREAD(restURI);
        EmployeesEntity[] employees = JsonArrayToEmployeesArray.getEmployeesArray(jsonArrayAsString);
        
        //no caching. allEmployees is always updated to the recent queried employees
        this.allEmployees = employees;        
        providerChangeSupport.fireProviderRefresh("allEmployees");       
    };
    
    public void updateEmployee(EmployeesEntity emp){
        String restURI = DeptEmpURIs.PostEmployeeUpdateURI();
        RestCallerUtil rcu = new RestCallerUtil();
        String jsonArrayAsString = rcu.invokeUPDATE(restURI, EmployeesEntityToJson.getJson(emp));
        
        //ensure employees collection is updated too        
        for (int i = 0; i < this.allEmployees.length; i++) {
            //if employeeId of the updated employee object matches the employeeId of an
            //existing object, replace the object with the updated one
            if(emp.getEmployeeId().compareTo(allEmployees[i].getEmployeeId()) == 0){
                //we found a match, so lets replace the object in the collection
                allEmployees[i] = emp;
                break;
            }
       }
        
    }
    
    public void createEmployee(Integer empId, String firstName, String lastName, Integer departmentId,
                                  Integer salary){
          
           /* ** default the following settings **
           * commissionPct 0.0
           * managerId = manager for department
           * job_id SA_REP
           * hire_date = today
           * email = firstName_firstCharacter+lastName
           */
          
           EmployeesEntity emp = new EmployeesEntity();
          
           emp.setEmployeeId(empId);
           emp.setCommissionPct(new Double(0.0));
          
           DepartmentsEntity department = this.getDepartmentById(departmentId);
           if(department != null){
               emp.setManagerId(department.getManagerId());
           }
          
           emp.setJobId("SA_REP");
          
           //add current day with no time information, just year, month and day
           SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
           String dateWithNoTime = sdf.format(GregorianCalendar.getInstance().getTime());
           try {
               emp.setHireDate(sdf.parse(dateWithNoTime));
           } catch (ParseException e) {
               e.printStackTrace();
           }

           String firstNameFirstCharacter = (firstName !=null && firstName!="")? firstName.substring(0,1) : "";           
           emp.setEmail((firstNameFirstCharacter+lastName).toUpperCase());

           emp.setFirstName(firstName);
           emp.setLastName(lastName);
           emp.setSalary(salary);

          
           //this is where all the infrastructure classes and methods become handy
           String restURI = DeptEmpURIs.PutDepartmentsCreateEmployeeURI(departmentId);
           RestCallerUtil rcu = new RestCallerUtil();
           String jsonString = rcu.invokeCREATE(restURI, EmployeesEntityToJson.getJson(emp));
          
           ArrayList emps = new ArrayList();
           for (int i = 0; i < allEmployees.length; i++) {
               //copy existing objects into list
               emps.add(allEmployees[i]);
          }
          //add new employee to list. Note that we don't check if the new employee existed. This
          //should be done in a production environment unless the employees data are re-read from
          //the service each time the emloyees detail page is displayed
          emps.add(emp);
          //update allEmployees array with new employee added

          allEmployees = (EmployeesEntity[]) emps.toArray(new EmployeesEntity[emps.size()]);
       }
    
    
    /**
     * get department by a provided department ID
     * @param departmentId
     * @return DepartmentsEntity object for the queried department. 
     *         returns null if department is not found
     * 
     */
    private DepartmentsEntity getDepartmentById(Integer departmentId){
    
        String restURI = DeptEmpURIs.GetDepartmentsByIdURI(departmentId);
        RestCallerUtil rcu = new RestCallerUtil();
        String jsonArrayAsString = rcu.invokeREAD(restURI);
        DepartmentsEntity[] departments = JsonArrayToDepartmentsArray.getDepartmentsArray(jsonArrayAsString);
        
        if(departments.length > 0){
            return departments[0];
        }
        else return null;
    }
    
    public void removeEmployee(Integer empId){
        String restURI = DeptEmpURIs.DeleteEmployeeRemoveURI(empId);
        RestCallerUtil rcu = new RestCallerUtil();
        String jsonArrayAsString = rcu.invokeDELETE(restURI);
    }


    public void setEditableEmployee(EmployeesEntity[] employeeToEdit){
        
        //create a copy of the object passed for edit. Without copying the employee data we 
        //would work on a object reference of the existing object, which makes it difficult 
        //to undo the user edits
        
        ArrayList  employeesToEditList = new ArrayList();
                
        if(employeeToEdit.length >0){
            employeesToEditList.add(employeeToEdit[0].clone());
        }
               
        this.editableEmployee = (EmployeesEntity[]) employeesToEditList.toArray(new EmployeesEntity[employeesToEditList.size()]);
    }

    public EmployeesEntity[] getEditableEmployee() {
        return editableEmployee;
    }
    
    
    //***** provider change support *****//
    //Enable provider change support
      protected transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);

      public void addProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.addProviderChangeListener(l);
      }

      public void removeProviderChangeListener(ProviderChangeListener l) {
         providerChangeSupport.removeProviderChangeListener(l);
      }


}
