package at.oefai.aaa.agent.jam;

/**
 * Represents one match found between a perception and the concerns(goals) of the agent.
 * @author Stefan Rank
 */
abstract class EventAppraisal extends AbstractFactAppraisal {
    // relevance for goals/intentions (conducive if >0 or obstructive if <0):
    private float relevance = 0;

    EventAppraisal(final float pRelevanceValue, final WorldModelRelation pRelation,
                   final Interpreter pInterpreter) {
        super(pRelation, pInterpreter);
        this.setRelevance(pRelevanceValue);
        // if new post an immediate emotion goal (impulse) with high 'utility' if emotional enough
        this.postImpulse();
        this.infoProcessingEffects(pInterpreter.getWorldModel());
        this.tryToCope();
    }

    public static EventAppraisal newEventAppraisal(final float pRelevanceValue, final WorldModelRelation pRelation,
            final Interpreter pInterpreter) {
        if (pRelation.isProspect()) { // prospect of something...
            if (pRelevanceValue > 0) { // ...good
                return new EventHopeAppraisal(pRelevanceValue, pRelation, pInterpreter);
            } else if (pRelevanceValue < 0) { // ...bad
                return new EventFearAppraisal(pRelevanceValue, pRelation, pInterpreter);
            }
        }
        switch (pRelation.getSuccessValue(null)) {
            case -1: // that it didnt happen was...
                if (pRelevanceValue > 0) { // ...good
                    return new EventReliefAppraisal(pRelevanceValue, pRelation, pInterpreter);
                } else if (pRelevanceValue < 0) { // ...bad
                    return new EventSadAppraisal(pRelevanceValue, pRelation, pInterpreter);
                }
                break;
            case 1: // that it happened was...
                if (pRelevanceValue > 0) { // ...good
                    return new EventJoyAppraisal(pRelevanceValue, pRelation, pInterpreter);
                } else if (pRelevanceValue < 0) { // ...bad
                    return new EventDistressAppraisal(pRelevanceValue, pRelation, pInterpreter);
                }
                break;
            default:
                // how did we get here???
        }
        assert false : "strange stuff happening when factoring an EventAppraisal";
        return null;
    }

    /** override to return a higher one for self initiated goal-actions (expected). */
    protected float getImpulseThreshold() {
        float th = super.getImpulseThreshold();
        if (this.getRelation().getResponsible().equals(this.getOwnerName())
                && (this.getRelation().getSuccessValue(null) != -1)) { // dont expect failure
            th += MY_EXPECTED_ACTION_IMPULSE_THRESHOLD_BONUS;
        }
        // if the action i apraised is a showexpression then causing it to show another one should be even harder
        // appraising showExpression in terms of goals should mainly lead to coping
        if (this.getRelation().getArgs().getFirst().eval(null).getString().equals("showExpression")) {
            th += IMPULSE_APPRAISAL_IMPULSE_THRESHOLD_BONUS;
        }
        return th;
    }

    private void setRelevance(final float pRelevanceValue) {
        this.relevance = pRelevanceValue;
    }

    public void update(final float relevanceValue) {
        this.setRelevance(relevanceValue);
    }

    public float getIntensity() {
        return super.getIntensity() * Math.abs(this.relevance);
    }

    // SP
    public float getSignedIntensity() {
        return super.getIntensity() * this.relevance;
    }

    protected abstract float getPreferenceChange();

    public final void infoProcessingEffects(final WorldModelTable pWorldModel) {
        // change the preference for the responsible one
        String responsible = this.getRelation().getResponsible();
        if (! responsible.equals(this.getOwnerName())) { // dont (dis)like myself for expected actions
            pWorldModel.changePreference(responsible, getPreferenceChange());
        }
    }

    protected StringBuffer valuesString() {
        return super.valuesString().append(" relevance: " + this.relevance);
    }

}
