package com.palmnest.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.palmnest.application.Constants;

/**
 * This class represents the basic "user" object in MobServer that allows for
 * authentication and user management. It implements Acegi Security's
 * UserDetails interface.
 *
 * @author <a href="mailto:chasel.java@gmail.com">Chasel Li</a>
 */
@Entity
@Table(name = "tb_app_user")
public class User implements Serializable, UserDetails {

	private static final long    serialVersionUID = -388927123830666500L;

	// Fields
	private              Long    id;
	private              String  username;
	private              String  password;
	private              String  passwordHint;
	private              String  telephone;
	private              String  fullName;
	private              Date    createdTime;
	private              Date    lastLoginTime;
	private              Date    lastUpdatedTime;
	private              String  lastUpdatedBy;
	private              String  citysysid;
	private              String  userCode;
	private              String  sex;
	private              Integer age;
	private              String  position;     //职位
	private              String  profession;   //工种
	private              String  skillLv;      //技能等级
	private              Date    empDate;        //入职日期
	private              String  photoUrl;
	private              Integer accountExpired;
	private              Integer accountLocked;
	private              Integer credentialsExpired;
	private              Integer accountEnabled;
	private              Integer version;
	private              String  epId;
	private              String  identifyNum;
	private              String  remark;
	private              Date    expiredTime;
	private              String  channel;
	private              Integer errornum;
	private              Integer isphonecheck;
	private              Integer userType;    //用户类型
	private              String  isenabled;
	private              String  shopPassword; //用于商城明文登录
	private              Integer deviceType;//手机登录设备类型
	private              String  deviceNo;//手机登录设备号
	private              Integer isOnline;//是否签到

	private Set<Role>      roles    = new HashSet<Role>();
	private Set<TbCompany> companys = new HashSet<TbCompany>();
	private Set<TbDept>    depts    = new HashSet<TbDept>();

//	private Set<TbOrganization> orgs=new HashSet<TbOrganization>(); 
//	private Set<FloorInfo> floors=new HashSet<FloorInfo>(); 

	/**
	 * default constructor
	 */
	public User() {
	}

	public User(final String username) {
		this.username = username;
	}

	// Property accessors
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "ID", unique = true)
	public Long getId() {
		return this.id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@JsonIgnore
	@Column(name = "ACCOUNT_EXPIRED")
	public Integer getAccountExpired() {
		return this.accountExpired;
	}

	public void setAccountExpired(Integer accountExpired) {
		this.accountExpired = accountExpired;
	}

	@JsonIgnore
	@Column(name = "ACCOUNT_LOCKED")
	public Integer getAccountLocked() {
		return this.accountLocked;
	}

	public void setAccountLocked(Integer accountLocked) {
		this.accountLocked = accountLocked;
	}

	@JsonIgnore
	@Column(name = "CREDENTIALS_EXPIRED")
	public Integer getCredentialsExpired() {
		return this.credentialsExpired;
	}

	public void setCredentialsExpired(Integer credentialsExpired) {
		this.credentialsExpired = credentialsExpired;
	}

	@JsonIgnore
	@Column(name = "ACCOUNT_ENABLED")
	public Integer getAccountEnabled() {
		return this.accountEnabled;
	}

	public void setAccountEnabled(Integer accountEnabled) {
		this.accountEnabled = accountEnabled;
	}

	@JsonIgnore
	@Column(name = "PASSWORD", length = 128)
	public String getPassword() {
		return this.password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@JsonIgnore
	@Column(name = "PASSWORD_HINT", length = 128)
	public String getPasswordHint() {
		return this.passwordHint;
	}

	public void setPasswordHint(String passwordHint) {
		this.passwordHint = passwordHint;
	}

	@JsonIgnore
	@Column(name = "TELEPHONE", length = 128)
	public String getTelephone() {
		return this.telephone;
	}

	public void setTelephone(String telephone) {
		this.telephone = telephone;
	}

	@Column(name = "USERNAME", length = 50)
	public String getUsername() {
		return this.username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Column(name = "FULL_NAME", length = 50)
	public String getFullName() {
		return this.fullName;
	}

	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	@JsonIgnore
	@Column(name = "VERSION")
	public Integer getVersion() {
		return this.version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	@JsonIgnore
	@Column(name = "EP_ID", length = 20)
	public String getEpId() {
		return this.epId;
	}

	public void setEpId(String epId) {
		this.epId = epId;
	}

	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "CREATED_TIME", length = 19)
	public Date getCreatedTime() {
		return this.createdTime;
	}

	public void setCreatedTime(Date createdTime) {
		this.createdTime = createdTime;
	}

	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "LAST_LOGIN_TIME", length = 19)
	public Date getLastLoginTime() {
		return this.lastLoginTime;
	}

	public void setLastLoginTime(Date lastLoginTime) {
		this.lastLoginTime = lastLoginTime;
	}

	@JsonIgnore
	@Column(name = "IDENTIFY_NUM")
	public String getIdentifyNum() {
		return this.identifyNum;
	}

	public void setIdentifyNum(String identifyNum) {
		this.identifyNum = identifyNum;
	}

	@JsonIgnore
	@Column(name = "REMARK", length = 40)
	public String getRemark() {
		return this.remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "LAST_UPDATED_TIME", length = 19)
	public Date getLastUpdatedTime() {
		return this.lastUpdatedTime;
	}

	public void setLastUpdatedTime(Date lastUpdatedTime) {
		this.lastUpdatedTime = lastUpdatedTime;
	}

	@JsonIgnore
	@Column(name = "LAST_UPDATED_BY", length = 40)
	public String getLastUpdatedBy() {
		return this.lastUpdatedBy;
	}

	public void setLastUpdatedBy(String lastUpdatedBy) {
		this.lastUpdatedBy = lastUpdatedBy;
	}

	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "EXPIRED_TIME", length = 19)
	public Date getExpiredTime() {
		return this.expiredTime;
	}

	public void setExpiredTime(Date expiredTime) {
		this.expiredTime = expiredTime;
	}

	@JsonIgnore
	@Column(name = "CITYSYSID", length = 50)
	public String getCitysysid() {
		return this.citysysid;
	}

	public void setCitysysid(String citysysid) {
		this.citysysid = citysysid;
	}

	@JsonIgnore
	@Column(name = "CHANNEL", length = 50)
	public String getChannel() {
		return this.channel;
	}

	public void setChannel(String channel) {
		this.channel = channel;
	}

	@JsonIgnore
	@Column(name = "ERRORNUM")
	public Integer getErrornum() {
		return this.errornum;
	}

	public void setErrornum(Integer errornum) {
		this.errornum = errornum;
	}

	@JsonIgnore
	@Column(name = "ISPHONECHECK")
	public Integer getIsphonecheck() {
		return this.isphonecheck;
	}

	public void setIsphonecheck(Integer isphonecheck) {
		this.isphonecheck = isphonecheck;
	}

	@JsonIgnore
	@Column(name = "USER_CODE", length = 28)
	public String getUserCode() {
		return userCode;
	}

	public void setUserCode(String userCode) {
		this.userCode = userCode;
	}

	@JsonIgnore
	@Column(name = "AGE")
	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@JsonIgnore
	@Column(name = "POSITION", length = 30)
	public String getPosition() {
		return position;
	}

	public void setPosition(String position) {
		this.position = position;
	}

	@JsonIgnore
	@Column(name = "PROFESSION", length = 30)
	public String getProfession() {
		return profession;
	}

	public void setProfession(String profession) {
		this.profession = profession;
	}

	@JsonIgnore
	@Column(name = "SKILL_LV", length = 30)
	public String getSkillLv() {
		return skillLv;
	}

	public void setSkillLv(String skillLv) {
		this.skillLv = skillLv;
	}

	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "EMP_DATE", length = 30)
	public Date getEmpDate() {
		return empDate;
	}

	public void setEmpDate(Date empDate) {
		this.empDate = empDate;
	}

	@Column(name = "PHOTO_URL", length = 50)
	public String getPhotoUrl() {
		return photoUrl;
	}

	public void setPhotoUrl(String photoUrl) {
		this.photoUrl = photoUrl;
	}

	@JsonIgnore
	@Column(name = "ISENABLED", length = 1)
	public String getIsenabled() {
		return isenabled;
	}

	public void setIsenabled(String isenabled) {
		this.isenabled = isenabled;
	}

	@Column(name = "shop_Password", length = 128)
	public String getShopPassword() {
		return shopPassword;
	}

	public void setShopPassword(String shopPassword) {
		this.shopPassword = shopPassword;
	}

	@JsonIgnore
	@Column(name = "USER_TYPE", length = 2)
	public Integer getUserType() {
		return userType;
	}

	public void setUserType(Integer userType) {
		this.userType = userType;
	}

	@Column(name = "SEX", length = 1)
	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}


	@Column(name = "device_type")
	public Integer getDeviceType() {
		return deviceType;
	}

	public void setDeviceType(Integer deviceType) {
		this.deviceType = deviceType;
	}

	@Column(name = "device_no")
	public String getDeviceNo() {
		return deviceNo;
	}

	public void setDeviceNo(String deviceNo) {
		this.deviceNo = deviceNo;
	}

	@Column(name = "is_online")
	public Integer getIsOnline() {
		return isOnline;
	}

	public void setIsOnline(Integer isOnline) {
		this.isOnline = isOnline;
	}

	@JsonIgnore
	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = "tr_app_user_role", joinColumns = {@JoinColumn(name = "USER_ID")}, inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
	public Set<Role> getRoles() {
		return roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}

	@JsonIgnore
	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = "tr_app_user_company", joinColumns = {@JoinColumn(name = "USER_ID")}, inverseJoinColumns = @JoinColumn(name = "COMP_ID"))
	public Set<TbCompany> getCompanys() {
		return companys;
	}

	public void setCompanys(Set<TbCompany> companys) {
		this.companys = companys;
	}

	@JsonIgnore
	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = "tr_app_user_dept", joinColumns = {@JoinColumn(name = "USER_ID")}, inverseJoinColumns = @JoinColumn(name = "DEPT_ID"))
	public Set<TbDept> getDepts() {
		return depts;
	}

	public void setDepts(Set<TbDept> depts) {
		this.depts = depts;
	}


//	@JsonIgnore
//	@ManyToMany(fetch = FetchType.EAGER)
//	@JoinTable(name = "tr_app_user_build_user", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = @JoinColumn(name = "org_id"))
//	public Set<TbOrganization> getOrgs() {
//		return orgs;
//	}
//
//	public void setOrgs(Set<TbOrganization> orgs) {
//		this.orgs = orgs;
//	}

//	@JsonIgnore
//	@ManyToMany(fetch = FetchType.EAGER)
//	@JoinTable(name = "tr_app_user_floor_user", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = @JoinColumn(name = "floor_id"))
//	public Set<FloorInfo> getFloors() {
//		return floors;
//	}
//
//	public void setFloors(Set<FloorInfo> floors) {
//		this.floors = floors;
//	}

	/*
	 * implements
	 * @Transient 不会持久化的属性
	 */
	@JsonIgnore
	@Transient
	public Set<GrantedAuthority> getAuthorities() {
		Set<GrantedAuthority> authorities = new LinkedHashSet<GrantedAuthority>();
		for (Role role : roles) {
			if (role.getRoleType().intValue() == 0) {
				role.setName(Constants.ADMIN_ROLE);
			} else {
			    role.setName(Constants.USER_ROLE);
			}
		}
		authorities.addAll(roles);
		return authorities;
	}

	@JsonIgnore
	@Transient
	public boolean isAccountNonExpired() {
		return true;
	}

	@JsonIgnore
	@Transient
	public boolean isAccountNonLocked() {
		return true;
	}

	@JsonIgnore
	@Transient
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@JsonIgnore
	@Transient
	public boolean isEnabled() {
		return true;
	}

	@JsonIgnore
	@Transient
	public boolean isAdmin() {
		if (this.userType != null && (this.userType == Constants.USER_TYPE_ADMIN || this.userType == Constants.USER_TYPE_SYSTEM_MANAGE)) {
			return true;
		} else {
			return false;
		}
	}

	@JsonIgnore
	@Transient
	public boolean isAdminAndProjectAdmin() {
		if (this.userType != null && (this.userType == Constants.USER_TYPE_ADMIN || this.userType == Constants.USER_TYPE_SYSTEM_MANAGE || this.userType == Constants.USER_TYPE_PROJECT_MANAGE || this.userType == Constants.USER_TYPE_GENERAL_MANAGE)) {
			return true;
		} else {
			return false;
		}
	}

	@JsonIgnore
	@Transient
	public List<LabelValue> getRoleList() {
		List<LabelValue> userRoles = new ArrayList<LabelValue>();
		if (this.roles != null) {
			for (Role role : roles) {
				userRoles.add(new LabelValue(role.getName(), role.getName()));
			}
		}
		return userRoles;
	}

	public void addRole(Role role) {
		getRoles().add(role);
	}

}