/*
 * Copyright (C) 2018 Tom Almy
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package us.almy.jelbum;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;

/**
 *
 * @author tom
 */
public class JelbumSolver {
    static AWord wordlist;
    
    public void solve(String leadingMatch, LinkedList<Integer> pattern, AWord target, LinkedList<String> answerText) {
        int size = pattern.removeFirst();
        if (pattern.isEmpty() && size == target.length) { 
            // Best case -- look for match with no spares. 
            for (AWord wlist = wordlist; wlist != null; wlist = wlist.next) {
                if (wlist.length != size || wlist.checksum != target.checksum ) {
                    continue;
                }
                if (wlist.equalMap(target)) { // We got one!
                    answerText.add(leadingMatch + wlist.text + "\n");
                }
            }
        } else if (pattern.isEmpty()) { 
            // Will be excess letters to ignore
            for (AWord wlist = wordlist; wlist != null; wlist = wlist.next) {
                if (wlist.length == size && wlist.fitMap(target)) { // We got one!
                    answerText.add(leadingMatch + wlist.text + "\n");
                }
            }
        } else {
            // Will be excess letters to process recursively
            for (AWord wlist = wordlist; wlist != null; wlist = wlist.next) {
                if (wlist.length == size && wlist.fitMap(target)) { // We got one!
                    AWord remainder = new AWord();
                    remainder.length = target.length-size;
                    for (int i = 0; i < 26; i++) {
                        remainder.map[i] = (byte)(target.map[i] - wlist.map[i]);
                    }
                    remainder.checksum = target.checksum - wlist.checksum;
                    // we don't need to update the text field since we don't use it
                    solve(leadingMatch+wlist.text+" ", new LinkedList<>(pattern), remainder, answerText);
                } 
            }
        }
    }
    
    public AWord makeAWord(String st) {
        AWord aWord = new AWord();

        aWord.length = st.length();
        for (int i = 0; i < aWord.length; i++) {
            // Process each character in the line;
            char ch = st.charAt(i);
            if (!Character.isLowerCase(ch)) {
                return null;
            }
            aWord.checksum += ch - 'a';
            aWord.map[ch - 'a']++;
        }
        return aWord;
    }
    
    public boolean readWords() {
        // The wordlist is effectively a singleton, so this function only executes 
        // if the wordlist has not been created
        if (wordlist != null) {
            return true;
        }

        BufferedReader myReader;
        String thisLine;
        int counter = 0;
        AWord lastWord = null;

        myReader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/us/almy/jelbum/wordlist.txt")));
        try {
            while ((thisLine = myReader.readLine()) != null) {
                if (thisLine.length() < 1 || thisLine.length() > 10) {
                    continue;
                }
                AWord aWord = makeAWord(thisLine);
                if (aWord == null) {
                    continue;
                }
                aWord.text = thisLine;
                if (wordlist == null) { // first in list
                    wordlist = aWord;
                } else { // additional words placed at tail to keep things in alphabetical order
                    lastWord.next = aWord;
                }
                lastWord = aWord;
                counter++;
            }
            myReader.close();
        } catch (IOException io) {
            return false;
        }
        return true;
    }
}
