package cn.com.qmth.stmms.biz.exam.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.BeanUtils;

import cn.com.qmth.stmms.biz.exam.bean.ExamStudentVo;
import cn.com.qmth.stmms.biz.mark.model.ProblemType;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.utils.ScoreItem;
import cn.com.qmth.stmms.common.annotation.ExcelField;
import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
import cn.com.qmth.stmms.common.utils.BigDecimalUtils;

/**
 * 针对某次考试的考生信息
 *
 * @author LS
 */
@Entity
@Table(name = "eb_exam_student")
public class ExamStudent implements Serializable {

    protected static final long serialVersionUID = 2944870647483950851L;

    public static final String ANSWER_SPLIT = ",";

    public static final String SPLIT = ";";

    public static final int SECRET_NUMBER_START = 10000000;

    public static final int SECRET_NUMBER_END = 99999999;

    @Id
    @GeneratedValue
    private Integer id;

    /**
     * 考试ID
     */
    @Column(name = "exam_id")
    private Integer examId;

    /**
     * 学校ID
     */
    @Column(name = "school_id")
    private Integer schoolId;

    /**
     * 学习中心
     */
    @Column(name = "campus_name", length = 32, nullable = true)
    private String campusName;

    /**
     * 科目代码
     */
    @Column(name = "subject_code", length = 32, nullable = false)
    @ExcelField(title = "课程代码*", align = 2, sort = 20)
    private String subjectCode;

    /**
     * 科目名称
     */
    @Column(name = "subject_name", length = 32, nullable = false)
    @ExcelField(title = "课程名称*", align = 2, sort = 30)
    private String subjectName;

    /**
     * 试卷类型
     */
    @Column(name = "paper_type", length = 8, nullable = false)
    private String paperType;

    /**
     * 准考证号
     */
    @Column(name = "exam_number", length = 64, nullable = false)
    @ExcelField(title = "准考证号*", align = 2, sort = 40)
    private String examNumber;

    /**
     * 学号
     */
    @Column(name = "student_code", length = 64, nullable = false)
    @ExcelField(title = "学号*", align = 2, sort = 50)
    private String studentCode;

    /**
     * 密号
     */
    @Column(name = "secret_number", length = 64, nullable = false)
    private String secretNumber;

    /**
     * 姓名
     */
    @Column(name = "name", length = 64, nullable = false)
    @ExcelField(title = "姓名*", align = 2, sort = 60)
    private String name;

    /**
     * 试卷袋签到表编号
     */
    @Column(name = "package_code", length = 64, nullable = true)
    @ExcelField(title = "签到表编号", align = 2, sort = 70)
    private String packageCode;

    /**
     * 考生考点信息
     */
    @Column(name = "exam_site", length = 32, nullable = true)
    @ExcelField(title = "考点信息", align = 2, sort = 80)
    private String examSite;

    /**
     * 考生考场信息
     */
    @Column(name = "exam_room", length = 32, nullable = true)
    @ExcelField(title = "考场信息", align = 2, sort = 90)
    private String examRoom;

    /**
     * 考生备注信息
     */
    @Column(name = "remark", length = 128, nullable = true)
    @ExcelField(title = "考生备注信息", align = 2, sort = 100)
    private String remark;

    /**
     * 扫描批次编号
     */
    @Column(name = "batch_code", length = 32, nullable = true)
    private String batchCode;

    /**
     * 原图数量
     */
    @Column(name = "sheet_count", nullable = false)
    private Integer sheetCount;

    /**
     * 裁切图数量
     */
    @Column(name = "slice_count", nullable = false)
    private Integer sliceCount;

    /**
     * 客观答案
     */
    @Column(name = "answers", nullable = true, columnDefinition = "text")
    private String answers;

    /**
     * 是否已上传
     */
    @Column(name = "is_upload", nullable = false)
    private boolean upload;

    /**
     * 是否缺考
     */
    @Column(name = "is_absent", nullable = false)
    private boolean absent;

    /**
     * 是否人工指定缺考
     */
    @Column(name = "is_manual_absent", nullable = false)
    private boolean manualAbsent;

    @Column(name = "is_breach", nullable = false)
    private boolean breach;

    /**
     * 是否数据校验异常
     */
    @Column(name = "is_exception", nullable = false)
    private boolean exception;

    /**
     * 是否数试评
     */
    @Column(name = "is_trial", nullable = false)
    private boolean trial;

    /**
     * 上传时间
     */
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "upload_time", nullable = true)
    private Date uploadTime;

    /**
     * 客观总分
     */
    @Column(name = "objective_score", nullable = true)
    private Double objectiveScore;

    /**
     * 客观题得分明细
     */
    @Column(name = "objective_score_list", nullable = true, columnDefinition = "text")
    private String objectiveScoreList;

    /**
     * 主观题状态
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "subjective_status", length = 16, nullable = false)
    private SubjectiveStatus subjectiveStatus;

    /**
     * 主观总分
     */
    @Column(name = "subjective_score", nullable = true)
    private Double subjectiveScore;

    /**
     * 主观题得分明细
     */
    @Column(name = "subjective_score_list", nullable = true, columnDefinition = "text")
    private String subjectiveScoreList;

    /**
     * 科目层次信息
     */
    @ExcelField(title = "层次", align = 2, sort = 110)
    @Column(name = "subject_level")
    private String subjectLevel;

    /**
     * 专业类型信息
     */
    @ExcelField(title = "专业类型", align = 2, sort = 120)
    @Column(name = "subject_category")
    private String subjectCategory;

    /**
     * 电厂
     */
    @ExcelField(title = "电厂*", align = 2, sort = 130)
    @Column(name = "college", length = 64, nullable = false)
    private String college;

    /**
     * 机组
     */
    @ExcelField(title = "机组*", align = 2, sort = 140)
    @Column(name = "class_name", length = 64, nullable = false)
    private String className;

    /**
     * 总评
     */
    @ExcelField(title = "总评*", align = 2, sort = 150)
    @Column(name = "teacher", length = 64, nullable = false)
    private String teacher;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "inspect_time", nullable = true)
    private Date inspectTime;

    /**
     * 复核人id
     */
    @Column(name = "inspector_id")
    private Integer inspectorId;

    @Column(name = "card_number", nullable = true)
    private Integer cardNumber;

    @Column(name = "inspect_count", nullable = true)
    private Integer inspectCount;

    /**
     * 当前轮次是否已复核
     */
    @Column(name = "inspected", nullable = false)
    private boolean inspected;

    /**
     * 成绩校验人ID
     */
    @Column(name = "score_verify_user")
    private Integer scoreVerifyUser;

    /**
     * 成绩校验时间
     */
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "score_verify_time")
    private Date scoreVerifyTime;

    /**
     * 成绩校验标记结果
     */
    @Column(name = "score_verify_flagged")
    private Boolean scoreVerifyFlagged;

    /**
     * 科目备注信息
     */
    @ExcelField(title = "科目备注信息", align = 2, sort = 160)
    @Transient
    private String subjectRemark;

    @Transient
    private ExamSubject subject;

    @Transient
    private List<String> sheetUrls;

    @Transient
    private List<String> packageUrls;

    @Transient
    private String answerUrl;

    @Transient
    private String markTime;

    @Transient
    private Integer libraryId;

    @Transient
    private int number;

    @Transient
    private String markLogin;

    @Transient
    private String markName;

    @Transient
    private String tagValue;

    @Transient
    private String examName;

    @Transient
    private User inspector;

    @Transient
    private List<ExamQuestion> subjectiveQuestionList;

    @Transient
    private List<ExamQuestion> objectiveQuestionList;

    @Transient
    private ProblemType problemType;

    @Transient
    private String problemUserName;

    @Transient
    private String problemRestTime;

    public Integer getId() {
        return id;
    }

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

    public Integer getExamId() {
        return examId;
    }

    public void setExamId(Integer examId) {
        this.examId = examId;
    }

    public String getCampusName() {
        return campusName;
    }

    public void setCampusName(String campusName) {
        this.campusName = campusName;
    }

    public String getSubjectCode() {
        return subjectCode;
    }

    public void setSubjectCode(String subjectCode) {
        this.subjectCode = subjectCode;
    }

    public String getExamNumber() {
        return examNumber;
    }

    public void setExamNumber(String examNumber) {
        this.examNumber = examNumber;
    }

    public String getName() {
        return name;
    }

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

    public String getSubjectName() {
        return subjectName;
    }

    public void setSubjectName(String subjectName) {
        this.subjectName = subjectName;
    }

    public String getStudentCode() {
        return studentCode;
    }

    public void setStudentCode(String studentCode) {
        this.studentCode = studentCode;
    }

    public String getAnswers() {
        return answers;
    }

    public void setAnswers(String answers) {
        this.answers = answers;
    }

    public boolean isUpload() {
        return upload;
    }

    public void setUpload(boolean upload) {
        this.upload = upload;
    }

    public Date getUploadTime() {
        return uploadTime;
    }

    public void setUploadTime(Date uploadTime) {
        this.uploadTime = uploadTime;
    }

    public List<String> getAnswerList() {
        String[] values = StringUtils.split(StringUtils.trimToNull(answers), ANSWER_SPLIT);
        List<String> list = new ArrayList<String>();
        if (values != null && values.length > 0) {
            for (String answer : values) {
                list.add(StringUtils.trim(answer));
            }
        }
        return list;
    }

    public Double getObjectiveScore() {
        return objectiveScore;
    }

    public void setObjectiveScore(Double objectiveScore) {
        this.objectiveScore = objectiveScore;
    }

    public Double getSubjectiveScore() {
        return subjectiveScore;
    }

    public void setSubjectiveScore(Double subjectiveScore) {
        this.subjectiveScore = subjectiveScore;
    }

    public String getObjectiveScoreList() {
        return objectiveScoreList;
    }

    public void setObjectiveScoreList(String objectiveScoreList) {
        this.objectiveScoreList = objectiveScoreList;
    }

    public String getSubjectiveScoreList() {
        return subjectiveScoreList;
    }

    public void setSubjectiveScoreList(String subjectiveScoreList) {
        this.subjectiveScoreList = subjectiveScoreList;
    }

    public static String buildScoreList(List<ScoreItem> scoreList) {
        if (scoreList != null) {
            return StringUtils.join(scoreList, SPLIT);
        } else {
            return null;
        }
    }

    public void setScoreList(List<ScoreItem> scoreList, boolean objective) {
        if (scoreList != null) {
            if (objective) {
                setObjectiveScoreList(StringUtils.join(scoreList, SPLIT));
            } else {
                setSubjectiveScoreList(StringUtils.join(scoreList, SPLIT));
            }
        }
    }

    public List<ScoreItem> getScoreList(boolean objective) {
        List<ScoreItem> scoreList = new LinkedList<ScoreItem>();
        try {
            String[] values = StringUtils.split(objective ? objectiveScoreList : subjectiveScoreList, SPLIT);
            for (String value : values) {
                ScoreItem item = ScoreItem.parse(value, objective);
                item.setObjective(objective);
                if (item != null) {
                    scoreList.add(item);
                }
            }
        } catch (Exception e) {
        }
        return scoreList;
    }

    public List<String> getSheetUrls() {
        return sheetUrls;
    }

    public void setSheetUrls(List<String> sheetUrls) {
        this.sheetUrls = sheetUrls;
    }

    public boolean isAbsent() {
        return absent;
    }

    public void setAbsent(boolean absent) {
        this.absent = absent;
    }

    public Integer getSheetCount() {
        return sheetCount;
    }

    public void setSheetCount(Integer sheetCount) {
        this.sheetCount = sheetCount;
    }

    public Integer getSliceCount() {
        return sliceCount;
    }

    public void setSliceCount(Integer sliceCount) {
        this.sliceCount = sliceCount;
    }

    public double getTotalScore() {
        double score = 0;
        if (objectiveScore != null) {
            score = BigDecimalUtils.add(score, objectiveScore);
        }
        if (subjectiveScore != null) {
            score = BigDecimalUtils.add(score, subjectiveScore);
        }
        return score;
    }

    public Integer getSchoolId() {
        return schoolId;
    }

    public void setSchoolId(Integer schoolId) {
        this.schoolId = schoolId;
    }

    public String getBatchCode() {
        return batchCode;
    }

    public void setBatchCode(String batchCode) {
        this.batchCode = batchCode;
    }

    public String getPackageCode() {
        return packageCode;
    }

    public void setPackageCode(String packageCode) {
        this.packageCode = packageCode;
    }

    public List<String> getPackageUrls() {
        return packageUrls;
    }

    public void setPackageUrls(List<String> packageUrls) {
        this.packageUrls = packageUrls;
    }

    public String getRemark() {
        return remark;
    }

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

    public String getMarkTime() {
        return markTime;
    }

    public void setMarkTime(String markTime) {
        this.markTime = markTime;
    }

    public boolean isException() {
        return exception;
    }

    public void setException(boolean exception) {
        this.exception = exception;
    }

    public String getObjectiveScoreString() {
        try {
            return ScoreItem.NUMBER_FORMAT.format(objectiveScore);
        } catch (Exception e) {
            return "";
        }
    }

    public String getSubjectiveScoreString() {
        try {
            return ScoreItem.NUMBER_FORMAT.format(subjectiveScore);
        } catch (Exception e) {
            return "";
        }
    }

    public String getTotalScoreString() {
        try {
            return ScoreItem.NUMBER_FORMAT.format(getTotalScore());
        } catch (Exception e) {
            return "";
        }
    }

    public String getSubjectRemark() {
        return subjectRemark;
    }

    public void setSubjectRemark(String subjectRemark) {
        this.subjectRemark = subjectRemark;
    }

    public String getSheetUrlString() {
        if (sheetUrls != null) {
            return StringUtils.join(sheetUrls, ",");
        } else {
            return "";
        }
    }

    public String getPackageUrlString() {
        if (packageUrls != null) {
            return StringUtils.join(packageUrls, ",");
        } else {
            return "";
        }
    }

    public String getAnswerUrl() {
        return answerUrl;
    }

    public void setAnswerUrl(String answerUrl) {
        this.answerUrl = answerUrl;
    }

    public String getSubjectLevel() {
        return subjectLevel;
    }

    public void setSubjectLevel(String subjectLevel) {
        this.subjectLevel = subjectLevel;
    }

    public String getExamSite() {
        return examSite;
    }

    public void setExamSite(String examSite) {
        this.examSite = examSite;
    }

    public String getExamRoom() {
        return examRoom;
    }

    public void setExamRoom(String examRoom) {
        this.examRoom = examRoom;
    }

    public String getSubjectCategory() {
        return subjectCategory;
    }

    public void setSubjectCategory(String subjectCategory) {
        this.subjectCategory = subjectCategory;
    }

    public Integer getLibraryId() {
        return libraryId;
    }

    public void setLibraryId(Integer libraryId) {
        this.libraryId = libraryId;
    }

    public ExamSubject getSubject() {
        return subject;
    }

    public void setSubject(ExamSubject subject) {
        this.subject = subject;
    }

    public boolean isBreach() {
        return breach;
    }

    public void setBreach(boolean breach) {
        this.breach = breach;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public String getMarkLogin() {
        return markLogin;
    }

    public void setMarkLogin(String markLogin) {
        this.markLogin = markLogin;
    }

    public String getMarkName() {
        return markName;
    }

    public void setMarkName(String markName) {
        this.markName = markName;
    }

    public String getTagValue() {
        return tagValue;
    }

    public void setTagValue(String tagValue) {
        this.tagValue = tagValue;
    }

    public boolean isManualAbsent() {
        return manualAbsent;
    }

    public void setManualAbsent(boolean manualAbsent) {
        this.manualAbsent = manualAbsent;
    }

    public String getPaperType() {
        return paperType;
    }

    public void setPaperType(String paperType) {
        this.paperType = paperType;
    }

    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        this.college = college;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getTeacher() {
        return teacher;
    }

    public void setTeacher(String teacher) {
        this.teacher = teacher;
    }

    public List<ExamQuestion> getSubjectiveQuestionList() {
        return subjectiveQuestionList;
    }

    public void setSubjectiveQuestionList(List<ExamQuestion> subjectiveQuestionList) {
        this.subjectiveQuestionList = subjectiveQuestionList;
    }

    public List<ExamQuestion> getObjectiveQuestionList() {
        return objectiveQuestionList;
    }

    public void setObjectiveQuestionList(List<ExamQuestion> objectiveQuestionList) {
        this.objectiveQuestionList = objectiveQuestionList;
    }

    public ProblemType getProblemType() {
        return problemType;
    }

    public void setProblemType(ProblemType problemType) {
        this.problemType = problemType;
    }

    public SubjectiveStatus getSubjectiveStatus() {
        return subjectiveStatus;
    }

    public void setSubjectiveStatus(SubjectiveStatus subjectiveStatus) {
        this.subjectiveStatus = subjectiveStatus;
    }

    public String getSecretNumber() {
        return secretNumber;
    }

    public void randomSecretNumber() {
        secretNumber = String.valueOf((int) (RandomUtils.nextDouble() * (SECRET_NUMBER_END - SECRET_NUMBER_START))
                + SECRET_NUMBER_START);
    }

    public Date getInspectTime() {
        return inspectTime;
    }

    public void setInspectTime(Date inspectTime) {
        this.inspectTime = inspectTime;
    }

    public void setSecretNumber(String secretNumber) {
        this.secretNumber = secretNumber;
    }

    public String getExamName() {
        return examName;
    }

    public void setExamName(String examName) {
        this.examName = examName;
    }

    public Integer getInspectorId() {
        return inspectorId;
    }

    public void setInspectorId(Integer inspectorId) {
        this.inspectorId = inspectorId;
    }

    public User getInspector() {
        return inspector;
    }

    public void setInspector(User inspector) {
        this.inspector = inspector;
    }

    public String getProblemUserName() {
        return problemUserName;
    }

    public void setProblemUserName(String problemUserName) {
        this.problemUserName = problemUserName;
    }

    public String getProblemRestTime() {
        return problemRestTime;
    }

    public void setProblemRestTime(String problemRestTime) {
        this.problemRestTime = problemRestTime;
    }

    public Integer getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(Integer cardNumber) {
        this.cardNumber = cardNumber;
    }

    public Integer getInspectCount() {
        return inspectCount;
    }

    public void setInspectCount(Integer inspectCount) {
        this.inspectCount = inspectCount;
    }

    public Integer getScoreVerifyUser() {
        return scoreVerifyUser;
    }

    public void setScoreVerifyUser(Integer scoreVerifyUser) {
        this.scoreVerifyUser = scoreVerifyUser;
    }

    public Date getScoreVerifyTime() {
        return scoreVerifyTime;
    }

    public void setScoreVerifyTime(Date scoreVerifyTime) {
        this.scoreVerifyTime = scoreVerifyTime;
    }

    public Boolean getScoreVerifyFlagged() {
        return scoreVerifyFlagged;
    }

    public void setScoreVerifyFlagged(Boolean scoreVerifyFlagged) {
        this.scoreVerifyFlagged = scoreVerifyFlagged;
    }

    public boolean getInspected() {
        return inspected;
    }

    public void setInspected(boolean inspected) {
        this.inspected = inspected;
    }

    public static ExamStudent of(ExamStudentVo vo) {
        ExamStudent e = new ExamStudent();
        BeanUtils.copyProperties(vo, e);
        return e;
    }

    public boolean isTrial() {
        return trial;
    }

    public void setTrial(boolean trial) {
        this.trial = trial;
    }

}
