package edu.northwestern.bioinformatics.studycalendar.domain;

import gov.nih.nci.cabig.ctms.domain.AbstractMutableDomainObject;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

@Entity
@Table (name = "users")
@GenericGenerator(name="id-generator", strategy = "native",
    parameters = {
        @Parameter(name="sequence", value="seq_users_id")
    }
)
public class User extends AbstractMutableDomainObject implements Named, Serializable, UserDetails {
    private String name;
    private Long csmUserId;
    private Set<UserRole> userRoles;
    private Boolean activeFlag;
    private List<StudySubjectAssignment> studySubjectAssignments;

    public User() {
        this.userRoles = new LinkedHashSet<UserRole>();
        this.studySubjectAssignments = new ArrayList<StudySubjectAssignment>();
        this.activeFlag = true;
    }

    ////// LOGIC

    @Transient
    public String getDisplayName() {
        return name;
    }

    public boolean hasRole(Role role) {
        return getUserRole(role) != null;
    }

    public UserRole getUserRole(Role role) {
        for (UserRole userRole : getUserRoles()) {
            if (role.equals(userRole.getRole())) return userRole;
        }
        return null;
    }

    public void addUserRole(UserRole userRole) {
        userRoles.add(userRole);
    }

    public void removeUserRole(UserRole userRole) {
        userRoles.remove(userRole);
    }

    public void clearUserRoles() {
        userRoles.clear();
    }

    public void addAllUserRoles(Set<UserRole> srcRoles) {
        this.userRoles.addAll(srcRoles);
    }

    public boolean hasAssignment(Site site) {
        for (StudySubjectAssignment assignment : getStudySubjectAssignments()) {
            if (assignment.getStudySite().getSite().equals(site)) return true;
        }
        return false;
    }

    public boolean hasAssignment(StudySite ss) {
        for (StudySubjectAssignment assignment : getStudySubjectAssignments()) {
            if (assignment.getStudySite().equals(ss)) return true;
        }
        return false;
    }

    ////// IMPLEMENTATION OF UserDetails

    public GrantedAuthority[] getAuthorities() {
        Role[] authorities = new Role[getUserRoles().size()];
        int i = 0;
        for (UserRole userRole : getUserRoles()) {
            authorities[i] = userRole.getRole();
            i++;
        }
        return authorities;
    }

    public String getPassword() {
        return "PASSWORD NOT AVAILABLE FOR " + getClass().getName();
    }

    public String getUsername() {
        return getName();
    }

    public boolean isAccountNonExpired() {
        return true;
    }

    public boolean isAccountNonLocked() {
        return true;
    }

    public boolean isCredentialsNonExpired() {
        return true;
    }

    public boolean isEnabled() {
        return getActiveFlag();
    }

    ////// BEAN PROPERTIES

    public String getName() {
        return name;
    }

    public Long getCsmUserId() {
        return csmUserId;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setCsmUserId(Long csmUserId) {
        this.csmUserId = csmUserId;
    }

    public Boolean getActiveFlag() {
        return activeFlag;
    }

    public void setActiveFlag(Boolean activeFlag) {
        this.activeFlag = activeFlag;
    }

    @OneToMany (mappedBy = "user")
    @Cascade( {CascadeType.ALL, CascadeType.DELETE_ORPHAN})
    public Set<UserRole> getUserRoles() {
        return userRoles;
    } 

    public void setUserRoles(Set<UserRole> userRoles) {
        this.userRoles = userRoles;
    }

    @OneToMany (mappedBy = "subjectCoordinator")
    @OrderBy // order by ID for testing consistency
    @Cascade (value = { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
    public List<StudySubjectAssignment> getStudySubjectAssignments() {
        return studySubjectAssignments;
    }

    public void setStudySubjectAssignments(List<StudySubjectAssignment> studySubjectAssignments) {
        this.studySubjectAssignments = studySubjectAssignments;
    }

    ////// OBJECT METHODS

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        return !(name != null ? !name.equals(user.name) : user.name != null);

    }

    @Override
    public int hashCode() {
        return (name != null ? name.hashCode() : 0);
    }
}

@@ -2635,16 +2635,31 @@
 etails%0A%0A
+    @Transient%0A
     publ
@@ -2695,24 +2695,24 @@
 orities() %7B%0A
-
         Role
@@ -2934,32 +2934,47 @@
 orities;%0A    %7D%0A%0A
+    @Transient%0A
     public Strin
@@ -3059,32 +3059,47 @@
 tName();%0A    %7D%0A%0A
+    @Transient%0A
     public Strin
@@ -3141,32 +3141,47 @@
 tName();%0A    %7D%0A%0A
+    @Transient%0A
     public boole
@@ -3227,32 +3227,47 @@
 rn true;%0A    %7D%0A%0A
+    @Transient%0A
     public boole
@@ -3312,32 +3312,47 @@
 rn true;%0A    %7D%0A%0A
+    @Transient%0A
     public boole
@@ -3402,32 +3402,47 @@
 rn true;%0A    %7D%0A%0A
+    @Transient%0A
     public boole

Add forgotten @Transients