package caseStudy;

import java.util.ArrayList;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class CrochetDB {
    // Data loaded into the DB from files
    private ArrayList<Stitch> stitchDefinitions;
    private ArrayList<CrochetPattern> patterns;
    private JFrame frame;
    private JScrollPane patternArea;
    
    // Main method
    public static void main(String[] args) {
        CrochetDB dbTest = new CrochetDB();        
        // Start the GUI
        // On exit, save the patterns and stitch dictionary
        dbTest.savePatterns();
        dbTest.saveStitchDictionary();
    }
    
    // Constructors
    public CrochetDB() {
        // Initialize the lists
        stitchDefinitions = new ArrayList<Stitch> ();
        patterns = new ArrayList<CrochetPattern> ();
        // Load the lists from the files
        loadStitches();
        loadPatterns();
        // Start the GUI
        startGUI();
    }
    // Define standard stitches
    private ArrayList<Stitch> defineStdStitches() {
        ArrayList<Stitch> standardStitches = new ArrayList<Stitch> (21);
        // Chain stitch (ch)
        standardStitches.add(new Stitch("Chain", "ch", "Yarn over, draw through loop."));
        // Single Crochet stitch (sc) plus increase (sc inc) and decrease (sc dec)
        standardStitches.add(new Stitch("Single Crochet", "sc",
                "Insert hook in next stitch, yarn over, draw loop through the stitch (2 loops on hook), "
                + "yarn over, draw through 2 loops to complete stitch."));
        standardStitches.add(new Stitch("Single Crochet Increase", "sc inc",
                "Work two single crochet stitches in one stitch from the previous row."));
        standardStitches.add(new Stitch("Single Crochet Decrease", "sc dec", 
                "Insert hook in next stitch, yarn over and draw loop through (2 loops on hook). Repeat with next stitch (3 loops on hook). "
                + "Yarn over and draw through 3 loops to complete stitch.", 2));
        // Half Double Crochet stitch (hdc) plus increase (hdc inc) and decrease (hdc dec)
        standardStitches.add(new Stitch("Half Double Crochet", "hdc",
                "Yarn over, insert hook into next stitch. Yarn over, draw through stitch (3 loops on hook). "
                + "Yarn over, draw through 3 loops to complete stitch."));
        standardStitches.add(new Stitch("Half Double Crochet Increase", "hdc inc",
                "Work two half double crochet stitches in one stitch from the previous row."));
        standardStitches.add(new Stitch("Half Double Crochet Decrease", "hdc dec", 
                "Yarn over, insert hook in next stitch, yarn over and draw loop through (3 loops on hook). "
                + "Insert hook in next stitch, yarn over and draw loop through (4 loops on hook). "
                + "Yarn over and draw through 4 loops to complete stitch.", 2));
        // Double Crochet stitch (dc) plus increase (dc inc) and decrease (dc dec)
        standardStitches.add(new Stitch("Double Crochet", "dc",
                "Yarn over, insert hook into next stitch. Yarn over, draw through stitch. (3 loops on hook)"
                + "Yarn over, draw through 2 loops on hook (2 loops on hook). "
                + "Yarn over, draw through 2 loops to complete stitch."));
        standardStitches.add(new Stitch("Double Crochet Increase", "dc inc",
                "Work two double crochet stitches in one stitch from the previous row."));
        standardStitches.add(new Stitch("Double Crochet Decrease", "dc dec", 
                "Yarn over, insert hook in next stitch, yarn over and draw loop through (3 loops on hook). "
                + "Yarn over, draw through 2 loops (2 loops on hook). "
                + "Yarn over, insert hook in next stitch, yarn over and draw loop through (4 loops on hook). "
                + "Yarn over and draw through 2 loops (3 loops on hook). "
                + "Yarn over, draw through 3 loops to complete stitch.", 2));
        // Triple Crochet stitch (tr) plus increase (tr inc) and decrease (tr dec)
        standardStitches.add(new Stitch("Triple Crochet", "tr",
                "Yarn over twice, insert hook into next stitch. Yarn over, draw through stitch. (4 loops on hook)"
                + "Yarn over, draw through 2 loops on hook (3 loops on hook). "
                + "Yarn over, draw through 2 loops on hook (2 loops on hook). "
                + "Yarn over, draw through 2 loops to complete stitch."));
        standardStitches.add(new Stitch("Triple Crochet Increase", "tr inc",
                "Work two triple crochet stitches in one stitch from the previous row."));
        standardStitches.add(new Stitch("Triple Crochet Decrease", "tr dec", 
                "Yarn over twice, insert hook in next stitch, yarn over and draw loop through stitch (4 loops on hook). "
                + "Yarn over, draw through 2 loops (3 loops on hook). "
                + "Yarn over, draw through 2 loops (2 loops on hook). "
                + "Yarn over twice, insert hook in next stitch, yarn over and draw loop through (5 loops on hook). "
                + "Yarn over and draw through 2 loops (4 loops on hook). "
                + "Yarn over and draw through 2 loops (3 loops on hook). "
                + "Yarn over, draw through 3 loops to complete stitch.", 2));
        // Slip stitch (sl st)
        standardStitches.add(new Stitch("Slip Stitch", "sl st",
                "Insert hook into next stitch. Yarn over, draw through stitch and loop on hook to complete stitch."));
        return standardStitches;
    }
    // Create standard stitch dictionary file
    private boolean saveStitchDictionary() {
        // Verify that the standard stitches haven't been deleted
        ArrayList<Stitch> standardStitches = defineStdStitches();
        for(Stitch s : standardStitches) {
            if (!stitchDefinitions.contains(s)) {
                stitchDefinitions.add(s);
            }
        }
        // Check if any stitches defined in the patterns are missing from the definition list
        for(CrochetPattern p : patterns) {
            for(Stitch s : p.getStitches()) {
                if (!stitchDefinitions.contains(s)) {
                    stitchDefinitions.add(s);
                }
            }
        }
        
        // TODO: Remove repeats
        
        // Write all stitches to the file
        try {
            File stitchDictionary = new File("StitchDictionary.txt");
            if (stitchDictionary.exists()) {
                stitchDictionary.delete();
            }
            stitchDictionary.createNewFile();
            FileWriter writer = new FileWriter(stitchDictionary);
            for (Stitch s : stitchDefinitions) {
                writer.write(s.save() + "\n");
            }
            writer.close();
            //System.out.println("Successfully created the stitch dictionary");
        } catch (IOException e) {
            System.out.println("An error occurred.");
            return false;
        }
        return true;
    }
    // Load stitch dictionary
    private boolean loadStitches() {
        try {
            File stitchDictionary = new File("StitchDictionary.txt");
            Scanner reader = new Scanner(stitchDictionary);
            while (reader.hasNextLine()) {
                stitchDefinitions.add(new Stitch(reader.nextLine()));
            }
            reader.close();
        } catch (FileNotFoundException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
            return false;
        }
        return true;
    }
    // Add a new stitch (not implemented)
    private void newStitchDef(Stitch s) {
        stitchDefinitions.add(s);
    }
    // Add a new pattern (not implemented)
    private void newPattern(CrochetPattern pattern) {
        patterns.add(pattern);
    }
    // Create a sample pattern
    private CrochetPattern createSamplePattern() {
        CrochetPattern sample = new CrochetPattern();
        Stitch magicRing = new Stitch("Magic Ring", "mg r", "It's complicated, look it up.", 0);
        Stitch pineapple = new Stitch("Pineapple Stitch", "pnl",
                "Yarn over, insert hook, draw up a loop. Repeat 3 more times. Yarn over, draw through all 9 loops.");
        sample.setName("Pineapple Square Scrubby");
        sample.setRecommendedHook(5.5);
        sample.setActualHook(3.75);
        // Gauge not important, leave as default values
        sample.addColour("Jolly", 22.1, 26.4, 9);
        sample.addStitch(magicRing);
        sample.addStitch(pineapple);
        sample.newRow("Start with a magic ring.", 0);
        sample.newRow("(pineapple st, ch 2) 7 times in magic ring. Make one more pineapple st, sl st to first pineapple st.", 8);
        sample.newRow("(pineapple st, ch 2) twice in one ch2 space, followed by (pineapple st, ch 2) in the next ch2 space."
                + " Repeat 3 more times. Sl st to first pineapple st.", 16);
        sample.newRow("(pineapple st, ch 2) twice in one ch2 space, followed by (pineapple st, ch 2) in the next ch2 space, "
                + "(pineapple st, ch 2) in th next ch2 space. Repeat 3 more times. Sl st to first pineapple st.", 20);
        return sample;
    }
    // Load saved patterns
    private boolean loadPatterns() {
        try {
            File savedPatterns = new File("Patterns.txt");
            Scanner reader = new Scanner(savedPatterns);
            while (reader.hasNextLine()) {
                patterns.add(new CrochetPattern(reader.nextLine()));
            }
            reader.close();
        } catch (FileNotFoundException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
            return false;
        }
        return true;
    }
    private boolean savePatterns() {
        // Verify that the sample pattern is in the list
        CrochetPattern sample = createSamplePattern();
        if (!patterns.contains(sample)) {
            patterns.add(sample);
        }
        
        // TODO: Remove repeats
        
        // Write to file
        try {
            File savedPatterns = new File("Patterns.txt");
            if (savedPatterns.exists()) {
                savedPatterns.delete();
            }
            savedPatterns.createNewFile();
            FileWriter writer = new FileWriter(savedPatterns);
            for (CrochetPattern p : patterns) {
                writer.write(p.save() + "\n");
            }
            writer.close();
            //System.out.println("Successfully saved the patterns.");
        } catch (IOException e) {
            System.out.println("An error occurred.");
            return false;
        }
        return true;
    }
    // Start GUI
    private void startGUI() {
        frame = new JFrame("Crochet Pattern Database");
        patternArea = new JScrollPane(displayPattern(null));
        frame.setLayout(new BorderLayout(10, 10));
        frame.setSize(900,900);
        frame.add(makeHeader(), BorderLayout.NORTH);
        frame.add(makePatternList(), BorderLayout.WEST);
        frame.add(patternArea, BorderLayout.CENTER);
        frame.setVisible(true);
    }
    private JLabel makeHeader() {
        JLabel header = new JLabel("Welcome to the Crochet Pattern Database and Viewer!");
        header.setBounds(10, 10, 100, 25);
        return header;
    }
    private JScrollPane makePatternList() {
        JPanel patternList = new JPanel();
        patternList.setLayout(new BoxLayout(patternList, BoxLayout.Y_AXIS));
        patternList.add(new JLabel("Patterns"));
        patternList.setSize(250, 900);
        for(CrochetPattern p : patterns) {
            JButton button = new JButton(p.getName());
            button.setSize(100, 40);
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e){
                    frame.remove(patternArea);
                    patternArea = new JScrollPane(displayPattern(p));
                    frame.add(patternArea, BorderLayout.CENTER);
                }  
            });
            patternList.add(button);
        }
        patternList.setVisible(true);
        JScrollPane patternListPane = new JScrollPane(patternList);
        patternListPane.setMaximumSize(new Dimension(250, 800));
        return patternListPane;
    }
    private JPanel displayPattern(CrochetPattern p) {
        if (p == null) {
            JPanel noPattern = new JPanel();
            noPattern.add(new JLabel("Please select a pattern"));
            return noPattern;
        }
        JPanel patternDisplay = new JPanel();
        patternDisplay.setLayout(new BoxLayout(patternDisplay, BoxLayout.Y_AXIS));
        patternDisplay.add(new JLabel(p.getName()));
        patternDisplay.add(new JLabel("Recommended hook size: " + p.getRecommendedHook()));
        if(p.getGauge() != null) {
            patternDisplay.add(new JLabel(p.getGauge().toString()));
        } else {
            patternDisplay.add(new JLabel("Gauge not important"));
        }
        int i=0;
        for(Row r : p.getRows()) {
            patternDisplay.add(new JLabel("Row " + i++ + ": "+ r.toString()));
        }
        patternDisplay.setVisible(true);
        return patternDisplay;
    }
}
