001package org.clafer.scope;
002
003import java.util.HashMap;
004import java.util.Map;
005import org.clafer.ast.AstClafer;
006
007/**
008 * Builder pattern for scopes. Use {@link Scope#builder()},
009 * {@link Scope#setScope(org.clafer.ast.AstClafer, int)}, {@link Scope#defaultScope(int)},
010 * {@link Scope#intLow}, or {@link Scope#intHigh} to construct the builder. The
011 * default scope and lowest and highest integers will be given a default if not
012 * set explicitly.
013 *
014 * @author jimmy
015 * @see Scope
016 */
017public class ScopeBuilder implements Scopable {
018
019    private final Map<AstClafer, Integer> scope;
020    private int defaultScope = 1;
021    private int intLow = -16;
022    private int intHigh = 16;
023
024    ScopeBuilder(Map<AstClafer, Integer> scope, int defaultScope, int intLow, int intHigh) {
025        this.scope = new HashMap<>(scope);
026        this.defaultScope = defaultScope;
027        this.intLow = intLow;
028        this.intHigh = intHigh;
029    }
030
031    ScopeBuilder() {
032        this.scope = new HashMap<>();
033    }
034
035    /**
036     * Set the scope of the Clafer. If the scope is already set for the Clafer,
037     * then the new scope overrides the previous one.
038     *
039     * @param clafer the Clafer
040     * @param scope the scope of the clafer
041     * @return this builder
042     */
043    public ScopeBuilder setScope(AstClafer clafer, int scope) {
044        this.scope.put(clafer, scope);
045        return this;
046    }
047
048    /**
049     * Adjust the scope of the Clafer. If the Clafer already has a scope then
050     * {@code newScope = oldScope + adjust}. Otherwise
051     * {@code newScope = defaultScope + adjust}.
052     *
053     * @param clafer the Clafer
054     * @param adjust increment the scope by this amount
055     * @return this builder
056     */
057    public ScopeBuilder adjustScope(AstClafer clafer, int adjust) {
058        Integer oldScope = scope.get(clafer);
059        scope.put(clafer, adjust + (oldScope == null ? defaultScope : oldScope.intValue()));
060        return this;
061    }
062
063    /**
064     * Set the scope for unspecified Clafers. If the default scope is already
065     * set, then the new default scope overrides the previous one.
066     *
067     * @param defaultScope the default scope
068     * @return this builder
069     */
070    public ScopeBuilder defaultScope(int defaultScope) {
071        this.defaultScope = defaultScope;
072        return this;
073    }
074
075    /**
076     * Adjust the scope of unspecified Clafers.
077     *
078     * @param adjust increment the default scope by this amount
079     * @return this builder
080     */
081    public ScopeBuilder adjustDefaultScope(int adjust) {
082        defaultScope += adjust;
083        return this;
084    }
085
086    /**
087     * Set the lowest (inclusive) integer used for solving. If the lowest
088     * integer is already set, then the new lowest integer overrides the
089     * previous one.
090     *
091     * @param intLow the lowest integer
092     * @return this builder
093     */
094    public ScopeBuilder intLow(int intLow) {
095        this.intLow = intLow;
096        return this;
097    }
098
099    /**
100     * Adjust the lowest integer used for solving.
101     *
102     * @param adjust increment the lowest integer by this amount
103     * @return this builder
104     */
105    public ScopeBuilder adjustIntLow(int adjust) {
106        intLow += adjust;
107        return this;
108    }
109
110    /**
111     * Set the highest (inclusive) integer used for solving. If the highest
112     * integer is already set, then the new highest integer overrides the
113     * previous one.
114     *
115     * @param intHigh the highest integer
116     * @return this builder
117     */
118    public ScopeBuilder intHigh(int intHigh) {
119        this.intHigh = intHigh;
120        return this;
121    }
122
123    /**
124     * Adjust the highest integer used for solving.
125     *
126     * @param adjust increment the highest integer by this amount
127     * @return this builder
128     */
129    public ScopeBuilder adjustIntHigh(int adjust) {
130        intHigh += adjust;
131        return this;
132    }
133
134    /**
135     * Finalizes all the decisions made in the builder. Further changes to this
136     * builder is permitted for building more scopes, but the returned scope
137     * will not be affected.
138     *
139     * @return the built scope
140     */
141    @Override
142    public Scope toScope() {
143        return new Scope(scope, defaultScope, intLow, intHigh);
144    }
145}