package org.diagbot.nlp.relation.analyze;

import org.algorithm.core.cnn.AlgorithmCNNExecutor;
import org.algorithm.core.cnn.entity.Lemma;
import org.algorithm.core.cnn.entity.Triad;
import org.algorithm.core.cnn.model.impl.RelationExtractionModelImpl;
import org.diagbot.nlp.feature.FeatureType;
import org.diagbot.nlp.participle.word.Lexeme;
import org.diagbot.nlp.participle.word.LexemePath;
import org.diagbot.nlp.relation.extract.*;
import org.diagbot.nlp.relation.module.*;
import org.diagbot.nlp.relation.module.cell.*;
import org.diagbot.nlp.relation.util.LemmaUtil;
import org.diagbot.nlp.relation.util.OutputInfo;
import org.diagbot.nlp.util.Constants;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.diagbot.nlp.participle.ParticipleUtil.participle;

/**
 * @ClassName org.diagbot.nlp.relation.StructureAnalyze
 * @Description 结构分析入口
 * @Author Mark Huang
 * @Date 2019/4/30 9:07
 * @Version 1.0
 **/
public class StructureAnalyze {

    private List<OutputInfo> outputInfos = new ArrayList<>();
    private static boolean updated = false;
    private static Object current = null;
    private static Object current_treat = null;
    private static String current_diag = "";
    private static BodyPart bodyPart = null;
    private static Negative negative = null;
    private static String direct = "";
    private static String num = "";
    private static String pacs_content = "";
    private static List<String> diag_con = Arrays.asList("门诊","诊断","入院","拟");
    private static List<String> past_con = Arrays.asList("既往","史","病史");
    private static String colon = ":|：|提示|示";
    private static String note = "";

    /**
     * 分词，提取词性，封装
     */
    public List<OutputInfo> extract(String content) {

        Lexeme lexeme = null;
        String timestamp = "";
        String[] tokens = content.split("，|。|；");

        try {

            initialize();
            for (String token:tokens) {

                System.out.println(current);

                note = content.substring(content.indexOf(token)+token.length(),
                        content.indexOf(token)+token.length()+1);
                System.out.println(token + "\t" + note);

                updated = false;

                preprocess(token, note);

                outputInfos.add(initOutputInfo());
                OutputInfo outputInfo = outputInfos.get(outputInfos.size()-1);

                LexemePath<Lexeme> lexemePath = participle(token, false);
                for (int i = 0; i < lexemePath.size(); i++) {
                    lexeme = lexemePath.get(i);
                    updateLexeme(lexeme);
                    updateInfo(outputInfo, lexeme);

                    if (current instanceof Pacs) {
                        if (lexeme.getProperty().equals(Constants.word_property_PACS)) {
                            String wd = lexeme.getText();
                            pacs_content = token.substring(token.indexOf(wd) + wd.length());
                        }
                    }

                }

                postprocess(token, outputInfo);
            }
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
        }
        finally {
            current = null;
            return outputInfos;
        }
    }

    public void initialize() {
        updated = false;
        current = null;
        current_treat = null;
        current_diag = "";
        bodyPart = null;
        num = "";
        pacs_content = "";
    }


    public void preprocess(String token, String note) {

    }

    public void postprocess(String token, OutputInfo outputInfo) {
        if (updated == false ||
                (getPropsize(outputInfo) == 1 && outputInfo.getSymptoms().get(0).getSymptomName().trim().length() == 0)){
            outputInfos.remove(outputInfos.size() - 1);
        }

        bodyPart = null;
        direct = "";
        negative = null;

        if (pacs_content.length() > 0) {
            current = outputInfo.getPacses().get(outputInfo.getPacses().size()-1);
            String[] arr = pacs_content.split(colon);
            pacs_content = arr[arr.length-1];
            outputInfo.getPacses().get(outputInfo.getPacses().size()-1).setValue(pacs_content);
            System.out.println(pacs_content);
            pacs_content = "";
        }
        else if (outputInfos.get(outputInfos.size()-1).getPacses().size() >= 1 && isUseful(token)) {
            current = outputInfos.get(outputInfos.size()-1).getPacses().get(0);
            ((Pacs)current).setValue(((Pacs)current).getValue() + "," + token);
        }
    }

    public void updateLexeme(Lexeme lexeme) {
        String prop = lexeme.getProperty();
        String[] lexprop = lexeme.getProperty().split(",");

        if (lexprop.length > 1) {
            prop = lexprop[0];
            for (int i=0;i<lexprop.length;i++) {
                if (current instanceof Treat && Arrays.asList(lexprop).indexOf(Constants.word_property_diagnose)>=0) {
                    prop = Constants.word_property_diagnose;
                }
                else if (Integer.parseInt(lexprop[i]) < Integer.parseInt(prop)) {
                    prop = lexprop[i];
                }
            }
        }
        lexeme.setProperty(prop);
    }

    public void updateInfo(OutputInfo outputInfo, Lexeme lexeme) {

        Symptom symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);;
        Lis lis = null;
        Pacs pacs = null;
        Vital vital = null;
        Treat treat = null;
        Past past = null;
        PD pd1 = null;

        try {

            switch (lexeme.getProperty()) {
                case Constants.word_property_prop:

                case Constants.word_property_degree:
                case Constants.word_property_degree_quan:

                case Constants.word_property_cause:
                case Constants.word_property_symptom:
                case Constants.word_property_vital_idx:
                case Constants.word_property_vital_result:
                    current = updateClinicalInfo(outputInfo, lexeme.getText(), lexeme.getProperty());
                    updated = true;
                    if (bodyPart != null) {
                        switch (lexeme.getProperty()) {
                            case Constants.word_property_symptom:
                                if (current instanceof Symptom) {
                                    ((Symptom)current).setBodyPart(bodyPart);
                                    bodyPart = null;
                                }
                                break;
                            case Constants.word_property_vital_idx:
                            case Constants.word_property_vital_result:
                                if (current instanceof Vital) {
                                    ((Vital)current).setBodyPart(bodyPart);
                                    bodyPart = null;
                                }
                                break;
                            case Constants.word_property_PACS:
                                if (current instanceof Pacs) {
                                    ((Pacs)current).setBodypart(bodyPart.getPartBodyName());
                                    bodyPart = null;
                                }
                                break;
                        }
                    }
                    break;
                case Constants.word_property_vital_value:
                    if (current instanceof Vital) {
                        vital = (Vital) current;
                        if (vital.getPd() == null) {
                            vital.setPd(new PD());
                        }
                        pd1 = vital.getPd();
                        pd1.setValue(lexeme.getText());
                        pd1.setUnit("");
                        updated = true;
                    }
                    break;
                case Constants.word_property_LIS:
                case Constants.word_property_LIS_Detail:
                    lis = new Lis();
                    lis.setLisName(lexeme.getText());
                    outputInfo.getLises().add(lis);
                    current = lis;
                    updated = true;
                    break;
                case Constants.word_property_LIS_Result:
                    if (current instanceof Lis) {
                        if (((Lis)current).getPd() == null) {
                            ((Lis)current).setPd(new PD());
                            pd1 = ((Lis)current).getPd();
                        }
                        pd1.setValue(lexeme.getText());
                        pd1.setUnit("");
                        updated = true;
                    }
                    break;
                case Constants.word_property_PACS:
                    pacs = new Pacs();
                    pacs.setPacsName(lexeme.getText());
                    if (bodyPart != null) {
                        pacs.setPacsName(bodyPart.getPartBodyName() + "+" + pacs.getPacsName());
                        bodyPart = null;
                    }
                    outputInfo.getPacses().add(pacs);
                    current = pacs;
                    updated = true;
                    break;
//                case Constants.word_property_PACS_Result:
//                    if (current instanceof Pacs) {
//                        if (((Pacs) current).getValue() == null) {
//                            ((Pacs) current).setValue("");
//                        }
//                        ((Pacs) current).setValue(((Pacs) current).getValue() + lexeme.getText() + ", ");
//                        updated = true;
//                    }
//                    break;
                case Constants.word_property_bodypart:
                    if (bodyPart == null) {
                        bodyPart = new BodyPart();
                        bodyPart.setPartBodyName(lexeme.getText());
                    }
                    else {
                        bodyPart.setPartBodyName(bodyPart.getPartBodyName() + "+" + lexeme.getText());
                    }

                    if (current instanceof Pacs) {
                        if (((Pacs)current).getBodypart()==null) {
                            ((Pacs)current).setBodypart("");
                        }
                        ((Pacs) current).setBodypart(((Pacs)current).getBodypart()+lexeme.getText() + ", ");
                    }

                    updated = true;
                    break;
                case Constants.word_property_direction:
                    if (current instanceof Pacs) {
                        if (((Pacs)current).getBodypart()==null) {
                            ((Pacs)current).setBodypart("");
                        }
                        ((Pacs) current).setBodypart(((Pacs)current).getBodypart()+lexeme.getText());
                        updated = true;
                    }
//                    else if (current instanceof Symptom) {
//                        PD pd = new PD();
//                        pd.setValue(lexeme.getText());
//                        pd.setUnit("");
//                        if (((Symptom)current).getPds() == null) {
//                            ((Symptom)current).setPds(new ArrayList<>());
//                        }
//                        ((Symptom)current).getPds().add(pd);
//                        updated = true;
//                    }
                    else {
                        direct = lexeme.getText();
                    }
                    break;
                case Constants.word_property_neg:
                    negative = new Negative();
                    negative.setNegaName(lexeme.getText());

                    updated = true;
                    break;
                case Constants.word_property_timestamp:
                    PD pd = new PD();
                    pd.setValue(lexeme.getText());
                    pd.setUnit("");
                    if (current instanceof Symptom) {
                        symptom = (Symptom)current;
                    }
                    else if (current == null && outputInfo.getSymptoms().get(0).getSymptomName() == "") {
                        symptom = outputInfo.getSymptoms().get(0);
                    }
                    if (symptom.getTimestamp() == null) {
                        List<PD> pds = new ArrayList<>();
                        pds.add(pd);
                        symptom.setTimestamp(pds);
                    }
                    else {
                        List<PD> pds = symptom.getTimestamp();
                        pds.add(pd);
                    }
                    updated = true;
                    current = symptom;

                    break;
                case Constants.word_property_freq:
                case Constants.word_property_number:
                    num = lexeme.getText();

                    updated = true;

                    break;
                case Constants.word_property_unit:
                    if (num.length() > 0) {
                        if (current instanceof Symptom) {
                            symptom = (Symptom) current;
                            if (symptom.getPds() == null) {
                                List<PD> pds1 = new ArrayList<>();
                                pds1.add(new PD());
                                symptom.setPds(pds1);
                            }
                            pd1 = symptom.getPds().get(symptom.getPds().size()-1);
                        } else if (current instanceof Vital) {
                            vital = (Vital) current;
                            if (vital.getPd() == null) {
                                vital.setPd(new PD());
                            }
                            pd1 = vital.getPd();
                        } else if (current instanceof Lis) {
                            lis = (Lis)current;
                            if (lis.getPd() == null) {
                                lis.setPd(new PD());
                            }
                            pd1 = lis.getPd();
                        } else if (current instanceof Past) {
                            past = (Past)current;
                            List<PD> pds1 = new ArrayList<>();
                            if (past.getPds() == null || past.getPds().size() == 0) {
                                past.setPds(pds1);
                            }
                            else { pds1 = past.getPds(); }
                            pds1.add(new PD());
                            pd1 = past.getPds().get(past.getPds().size() - 1);
                        } else if (current instanceof Treat) {
                            treat = (Treat)current;
                            List<PD> pds1 = new ArrayList<>();
                            if (treat.getPds() == null || treat.getPds().size() == 0) {
                                treat.setPds(pds1);
                            }
                            else {
                                pds1 = treat.getPds();
                            }
                            pds1.add(new PD());
                            pd1 = treat.getPds().get(treat.getPds().size()-1);
                        }

                        pd1.setValue(num);
                        pd1.setUnit(lexeme.getText());
                        updated = true;
                        num = "";
                    }
                    break;
                case Constants.word_property_time:
                    if (num.length() > 0) {
                        if (current instanceof Past) {
                            List<PD> pds1 = new ArrayList<>();
                            pds1.add(new PD());
                            ((Past)current).setPds(pds1);
                            pd1 = pds1.get(0);
                            pd1.setValue(num);
                            pd1.setUnit(lexeme.getText());
                            updated = true;
                            num = "";
                            current = null;
                        }
                        else if (current_diag.length() > 0) {
                            if (outputInfo.getPasts() == null || outputInfo.getPasts().size() == 0) {
                                outputInfo.getPasts().add(new Past());
                            }
                            past = outputInfo.getPasts().get(outputInfo.getPasts().size() - 1);
                            past.setDiagnose(current_diag);
                            past.setPds(new ArrayList<>());
                            pd1 = new PD();
                            pd1.setValue(num);
                            pd1.setUnit(lexeme.getText());
                            past.getPds().add(pd1);

                            current = past;
                            current_diag = "";
                        }
                        else {
                            if (symptom.getTimestamp() == null) {
                                List<PD> pds1 = new ArrayList<>();
                                pds1.add(new PD());
                                symptom.setTimestamp(pds1);
                            }
                            else {
                                symptom.getTimestamp().add(new PD());
                            }
                            pd1 = symptom.getTimestamp().get(symptom.getTimestamp().size()-1);
                            pd1.setValue(num);
                            pd1.setUnit(lexeme.getText());
                            updated = true;
                            num = "";
                            current = symptom;
                        }
                    }
                    break;
                case Constants.word_property_diagnose:
                case Constants.word_property_med:
                case Constants.word_property_med_com:
                case Constants.word_property_treat:
                    current = updateClinicalInfo(outputInfo, lexeme.getText(), lexeme.getProperty());
                    updated = true;
                    break;
                case Constants.word_property_other:
                default:
                    if (diag_con.indexOf(lexeme.getText()) >= 0) {
                        outputInfo.getTreats().add(new Treat());
                        treat = outputInfo.getTreats().get(outputInfo.getTreats().size() - 1);
                        if (current_diag.length() > 0) {
                            treat.setDiagnose(current_diag);
                            current_diag = "";
                            current = null;
                        }
                        current = treat;
                    }
                    else if (past_con.indexOf(lexeme.getText()) >= 0) {
                        if (outputInfo.getPasts() == null || outputInfo.getPasts().size() == 0) {
                            outputInfo.getPasts().add(new Past());
                        }
                        past = outputInfo.getPasts().get(outputInfo.getPasts().size() - 1);
                        if (current_diag != "") {
                            past.setDiagnose(current_diag);
                            current_diag = "";
                        }
                        current = past;
                    }
                    break;
            }
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public OutputInfo initOutputInfo() {
        OutputInfo outputInfo = new OutputInfo();

        outputInfo.setSymptoms(new ArrayList<>());
        outputInfo.getSymptoms().add(new Symptom());
        outputInfo.getSymptoms().get(outputInfo.getSymptoms().size()-1).setSymptomName("");

        outputInfo.setVitals(new ArrayList<>());

        outputInfo.setPasts(new ArrayList<>());

        outputInfo.setLises(new ArrayList<>());

        outputInfo.setPacses(new ArrayList<>());

        outputInfo.setTreats(new ArrayList<>());

        return outputInfo;
    }

    public int getPropsize(OutputInfo outputInfo) {
        int size = outputInfo.getSymptoms().size() + outputInfo.getVitals().size() +
                outputInfo.getPasts().size() + outputInfo.getLises().size() +
                outputInfo.getPacses().size() + outputInfo.getTreats().size();

        return size;
    }


    public Boolean checkSymptom(Symptom symptom) {
        Boolean isfilled = false;

        if (symptom.getSymptomName().trim().length() > 0 || symptom.getNegative() != null
                || symptom.getProperty() != null || symptom.getCause() != null
                || symptom.getBodyPart() != null || symptom.getDegree() != null
                || symptom.getTimestamp() != null || symptom.getPds() != null) {
            isfilled = true;
        }
        return isfilled;
    }


    public Object updateClinicalInfo(OutputInfo outputInfo, String name, String type) {

        Object obj = null;
        Symptom symptom = null;
        Treat treat = null;
        Past past = null;

        System.out.println(name + "\t" + type);
        switch (type) {
            case Constants.word_property_symptom:
                symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);

                if (symptom.getSymptomName() == null || symptom.getSymptomName().trim().length() == 0) {
                    symptom.setSymptomName(name);
                }
                else {
                    symptom.setSymptomName(symptom.getSymptomName() + ", " + name);
                }

                if (negative != null) {
                    symptom.setSymptomName(negative.getNegaName()+symptom.getSymptomName());
                    negative = null;
                }

                if (direct.length() > 0) {
                    if (symptom.getPds() == null) {
                        symptom.setPds(new ArrayList());
                        symptom.getPds().add(new PD());
                    }
                    PD pd = symptom.getPds().get(symptom.getPds().size()-1);
                    pd.setValue(direct);
                    pd.setUnit("");
                    direct = "";
                }

                obj = symptom;
                break;
            case Constants.word_property_vital_idx:
            case Constants.word_property_vital_result:
                if (outputInfo.getVitals().size() == 0) {
                    outputInfo.getVitals().add(new Vital());
                }

                Vital vital = outputInfo.getVitals().get(outputInfo.getVitals().size()-1);

                if (vital.getVitalName() == null || vital.getVitalName().trim().length() == 0) {
                    vital.setVitalName(name);
                }
                else {
                    vital.setVitalName(vital.getVitalName() + "," + name);
                }

                obj = vital;
                break;
            case Constants.word_property_diagnose:
                if (current instanceof Past) {
                    past = (Past)current;

                    if (past.getDiagnose() == null || past.getDiagnose().trim().length() == 0) {
                        past.setDiagnose(name);
                    } else {
                        past.setDiagnose(past.getDiagnose() + "," + name);
                    }

                    obj = past;
                    current_treat = past;
                }
                else //{
                    if (current instanceof Treat) {
                        treat = (Treat) current;
                        /*
                    }
                    else {
                        if (outputInfo.getTreats().size() == 0) {
                            outputInfo.getTreats().add(new Treat());
                        }
                        treat = outputInfo.getTreats().get(outputInfo.getTreats().size() - 1);
                    }
                    */
                    if (treat.getDiagnose() == null || treat.getDiagnose().trim().length() == 0) {
                        treat.setDiagnose(name);
                    } else {
                        treat.setDiagnose(treat.getDiagnose() + "," + name);
                    }

                    obj = treat;
                    current_treat = treat;
                }
                else {
                    current_diag = name;
                }
                break;
            case Constants.word_property_cause:
                Cause cause = new Cause();
                cause.setCauseName(name);

                if (current instanceof Symptom) {
                    symptom = (Symptom)current;
                }
                else {
                    symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);
                }

                if (symptom.getCause() != null) {
                    if (!outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1).getSymptomName().equals(symptom.getSymptomName())) {
                        outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1).setSymptomName(symptom.getSymptomName());
                        symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);
                    }
                }
                symptom.setCause(cause);

                obj = symptom;

                break;
            case Constants.word_property_degree:
            case Constants.word_property_degree_quan:
                Degree degree = new Degree();
                degree.setDegreeName(name);

                if (current instanceof Vital) {
                    ((Vital)current).setDegree(degree);
                    obj = current;
//                    symptom = (Symptom)current;
//                }
//                else {
//                    symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);
                }

                else if (current instanceof Symptom) {
                    symptom = (Symptom)current;

                    if (symptom.getDegree() != null) {
                        if (!outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1).getSymptomName().equals(symptom.getSymptomName())) {
                            outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1).setSymptomName(symptom.getSymptomName());
                            symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);
                        }
                    }
                    symptom.setDegree(degree);

                    obj = symptom;
                }
                break;
            case Constants.word_property_prop:
                Property property = new Property();
                property.setPropertyName(name);

                if (negative != null) {
                    property.setPropertyName(negative.getNegaName()+property.getPropertyName());
                    negative = null;
                }

                symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);

                if (symptom.getProperty() != null) {
                    if (!outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1).getSymptomName().equals(symptom.getSymptomName())) {
                        outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1).setSymptomName(symptom.getSymptomName());
                        symptom = outputInfo.getSymptoms().get(outputInfo.getSymptoms().size() - 1);
                    }
                }
                symptom.setProperty(property);
                obj = symptom;
                break;
            case Constants.word_property_treat:
                if (current instanceof Treat) {
                    treat = (Treat)current;
                    if (treat.getValue() == null || treat.getValue().trim().length() == 0) {
                        treat.setValue(name);
                    }
                    else {
                        treat.setValue(treat.getValue() + "," + name);
                    }
                    current_treat = treat;
                    obj = treat;
                }
                else if (current_treat instanceof Past) {
                    past = (Past)current_treat;
                    if (past.getValue() == null || past.getValue().trim().length() == 0) {
                        past.setValue(name);
                    }
                    else {
                        past.setValue(past.getValue() + "," + name);
                    }

                    obj = past;
                }
                else /*if (outputInfo.getTreats().size() == 0)*/ {
                    outputInfo.getTreats().add(new Treat());
                    treat = outputInfo.getTreats().get(outputInfo.getTreats().size() - 1);

                    treat.setValue(name);
                    current_treat = treat;
                    obj = treat;
                }
                break;
            case Constants.word_property_med:
            case Constants.word_property_med_com:
                if (current_treat instanceof Past || current instanceof Past) {
                    if (current_treat instanceof Past) {
                        past = (Past) current_treat;
                    }
                    else if (current instanceof Past) {
                        past = (Past) current;
                    }

                    if (past.getTreatName() == null || past.getTreatName().trim().length() == 0) {
                        past.setTreatName(name);
                    } else {
                        past.setTreatName(past.getTreatName() + "," + name);
                    }

                    obj = past;
                }
                else {
                    if (!(current instanceof Treat)) {
                        current = updateClinicalInfo(outputInfo, "", Constants.word_property_treat);
                    }
                    treat = (Treat) current;

                    if (treat.getTreatName() == null || treat.getTreatName().trim().length() == 0) {
                        treat.setTreatName(name);
                    } else {
                        treat.setTreatName(treat.getTreatName() + "," + name);
                    }
                    obj = treat;
                }
                break;
        }

//        printcurrentobj(obj);
        return obj;
    }

    public Boolean isUseful(String token) {
        Boolean useful = false;
        String[] pacstype = {"3","17","18","19"};
        try {
            LexemePath<Lexeme> lexemes = participle(token, false);
            for (Lexeme lexeme : lexemes) {
                if (Arrays.asList(pacstype).indexOf(lexeme.getProperty())>=0) {
                    useful = true;
                    break;
                }
            }
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        finally {
            return useful;
        }
    }

    public void printcurrentobj(Object obj) {
        if (obj instanceof Symptom) {
            Symptom symptom = (Symptom)obj;
            System.out.println("Symptom:\t" + symptom.getSymptomName() );
        }
        else if (obj instanceof Vital) {
            Vital vital = (Vital)obj;
            System.out.println("Vital:\t" + vital.getVitalName() );
        }
        else if (obj instanceof Treat) {
            Treat treat = (Treat)obj;
            System.out.println("Treat:\t" + treat.getTreatName() + "\t" + treat.getDiagnose() );
        }
        else {
            System.out.println(obj);
        }
    }
}
