/**
 * Copyright 2005-2018 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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 org.kuali.rice.kim.bo.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.log4j.Logger;
import org.eclipse.persistence.annotations.JoinFetch;
import org.eclipse.persistence.annotations.JoinFetchType;
import org.kuali.rice.kim.api.services.KimApiServiceLocator;
import org.kuali.rice.kim.api.type.KimAttributeField;
import org.kuali.rice.kim.bo.impl.KimAttributes;
import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator;
import org.kuali.rice.kim.framework.type.KimTypeService;
import org.kuali.rice.kim.impl.role.RoleBo;
import org.kuali.rice.kim.impl.role.RoleResponsibilityBo;
import org.kuali.rice.kim.impl.type.KimTypeBo;
import org.kuali.rice.kim.service.KIMServiceLocatorInternal;
import org.springframework.util.AutoPopulatingList;
import org.springframework.util.StringUtils;

/**
 * This is a description of what this class does - shyu don't forget to fill this in. 
 * 
 * @author Kuali Rice Team (rice.collab@kuali.org)
 *
 */
@Entity
@Table(name = "KRIM_PND_ROLE_MT")
public class PersonDocumentRole extends KimDocumentBoActivatableEditableBase {
    private static final Logger LOG = Logger.getLogger(PersonDocumentRole.class);
    private static final long serialVersionUID = 4908044213007222739L;

    @Id
    @Column(name = "ROLE_ID")
    protected String roleId;

    @Column(name = "KIM_TYP_ID")
    protected String kimTypeId;

    @Column(name = "ROLE_NM")
    protected String roleName;

    @Transient
    protected RoleBo roleBo;

    @Column(name = "NMSPC_CD")
    protected String namespaceCode;

    @Transient
    protected KimTypeBo kimRoleType;

    @Transient
    protected List<? extends KimAttributes> attributes;

    @Transient
    protected transient List<KimAttributeField> definitions;

    @Transient
    protected transient Map<String, Object> attributeEntry;

    @JoinFetch(value= JoinFetchType.OUTER)
    @OneToMany(targetEntity = KimDocumentRoleMember.class, orphanRemoval = true, cascade = { CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.PERSIST })
    @JoinColumns({ 
        @JoinColumn(name = "FDOC_NBR", referencedColumnName = "FDOC_NBR", insertable = false, updatable = false), 
        @JoinColumn(name = "ROLE_ID", referencedColumnName = "ROLE_ID", insertable = false, updatable = false) })
    protected List<KimDocumentRoleMember> rolePrncpls;

    @Transient
    protected KimDocumentRoleMember newRolePrncpl;

    @Transient
    protected boolean isEditable = true;

    public PersonDocumentRole() {
        attributes = new ArrayList<KimAttributes>();
        rolePrncpls = new ArrayList<KimDocumentRoleMember>();
        attributeEntry = new HashMap<String, Object>();
    }

    public String getRoleId() {
        return this.roleId;
    }

    public void setRoleId(String roleId) {
        this.roleId = roleId;
    }

    public String getKimTypeId() {
        return this.kimTypeId;
    }

    public void setKimTypeId(String kimTypeId) {
        this.kimTypeId = kimTypeId;
    }

    public String getRoleName() {
        return this.roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public List<? extends KimAttributes> getAttributes() {
        return this.attributes;
    }

    public void setAttributes(List<? extends KimAttributes> attributes) {
        this.attributes = attributes;
    }

    public KimTypeBo getKimRoleType() {
        if (kimRoleType == null && StringUtils.hasText(kimTypeId)) {
            kimRoleType = KimTypeBo.from(KimApiServiceLocator.getKimTypeInfoService().getKimType(kimTypeId));
        }
        return kimRoleType;
    }

    public Map<String, KimAttributeField> getDefinitionsKeyedByAttributeName() {
        final Map<String, KimAttributeField> map = new HashMap<String, KimAttributeField>();
        for (KimAttributeField field : getDefinitions()) {
            map.put(field.getAttributeField().getName(), field);
        }
        return map;
    }

    public List<KimAttributeField> getDefinitions() {
        if (definitions == null || definitions.isEmpty()) {
            KimTypeService kimTypeService = KimFrameworkServiceLocator.getKimTypeService(KimTypeBo.to(this.getKimRoleType()));
            //it is possible that the the roleTypeService is coming from a remote application                        
            // and therefore it can't be guarenteed that it is up and working, so using a try/catch to catch this possibility.                       
            try {
                if (kimTypeService != null) {
                    definitions = kimTypeService.getAttributeDefinitions(getKimTypeId());
                } else {
                    definitions = Collections.emptyList();
                }
            } catch (Exception ex) {
                LOG.warn("Not able to retrieve KimTypeService from remote system for KIM Role Type: " + this.getKimRoleType(), ex);
            }
        }
        return definitions;
    }

    public void setDefinitions(List<KimAttributeField> definitions) {
        this.definitions = definitions;
    }

    public Map<String, Object> getAttributeEntry() {
        if (attributeEntry == null || attributeEntry.isEmpty()) {
            attributeEntry = KIMServiceLocatorInternal.getUiDocumentService().getAttributeEntries(getDefinitions());
        }
        return this.attributeEntry;
    }

    public void setAttributeEntry(Map<String, Object> attributeEntry) {
        this.attributeEntry = attributeEntry;
    }

    public List<KimDocumentRoleMember> getRolePrncpls() {
        return this.rolePrncpls;
    }

    public void setRolePrncpls(List<KimDocumentRoleMember> rolePrncpls) {
        this.rolePrncpls = rolePrncpls;
    }

    public KimDocumentRoleMember getNewRolePrncpl() {
        return this.newRolePrncpl;
    }

    public void setNewRolePrncpl(KimDocumentRoleMember newRolePrncpl) {
        this.newRolePrncpl = newRolePrncpl;
    }

    public String getNamespaceCode() {
        return this.namespaceCode;
    }

    public void setNamespaceCode(String namespaceCode) {
        this.namespaceCode = namespaceCode;
    }

    /**
	 * @return the roleBo
	 */
    public RoleBo getRoleBo() {
        return this.roleBo;
    }

    /**
	 * @param roleBo the roleBo to set
	 */
    public void setRoleBo(RoleBo roleBo) {
        this.roleBo = roleBo;
    }

    /**
	 * @return the isEditable
	 */
    public boolean isEditable() {
        return this.isEditable;
    }

    /**
	 * @param isEditable the isEditable to set
	 */
    public void setEditable(boolean isEditable) {
        this.isEditable = isEditable;
    }
}
