/home/caleb/ASDV-Java/Semester 2/Assignments/MP5_CalebFontenot/src/main/java/com/calebfontenot/mp5_calebfontenot/NormalizeDatabase.java
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.calebfontenot.mp5_calebfontenot;

/**
 *
 * @author caleb
 */
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
import java.util.ArrayList;

/**
 *
 * @author ASDV2
 */
public class NormalizeDatabase
{
/**Finds the closure of a set of attributes given a set of FDs of a relation R
 * 
 * @param attributes attributes to find their closure
 * @param fds set of FDs of  relation R
 * @return the closure of the parameter attributes.
 */
    public static String closure(String attributes, ArrayList<FD> fds )
    {
        attributes = attributes.toUpperCase();
        for (int j = 0; j < fds.size(); ++j)
        {
            FD capitalsFD = new FD(fds.get(j).getLhs().toUpperCase(),
                                    fds.get(j).getRhs().toUpperCase());
            fds.set(j, capitalsFD);
        }
        //        1. Set x+ = x
        String closure = attributes;
        String closurePreveious = attributes;
//        2. Starting with x+ apply each FD xF —> y in F where
//          xF belongs in closure x+ but but the rhs y is not already in x+, to find determined
//          attributes y
//        3. x+ = x+ U y

        while (true)
        {
            
            for (int i = 0; i < fds.size(); ++i)
            {
                if (closure.contains(fds.get(i).getRhs()))
                    continue;
                // if the left hand side of the FD is contained in the closure
                // then add to the closure the RHS of the FD
                if (closure.contains(fds.get(i).getLhs()))
                        closure += fds.get(i).getRhs();
            }
            if (closurePreveious.equals(closure))
                break;
            else 
                closurePreveious = closure;
        }

//        4, If y not empty goto (2)
//        5. Return x+
        return closure;

    }
    /**
     * Eliminates redundant attributes from the LHS of each FD of a set of FDs
     * given as parameters.
     *
     * @param fds the set of FDs to eliminate the redundancy
     * @return and ArrayList with no redundancy on LHS of each FD.
     */
    public static ArrayList<FD> eliminateRedundantAttributes(ArrayList<FD> fds)
    {
        for (int j = 0; j < fds.size(); ++j)
        {
            int s = fds.get(j).getLhs().length();
            if (s < 2)
            {
                continue;
            }
            else 
            {
               String fl = fds.get(j).getLhs().substring(0, 1);
                ArrayList<FD> fFD = new ArrayList<FD>();
                String s1 = " ";
                if (fds.get(j).getLhs().length() == 2)
                { 
                    s1 = fds.get(j).getLhs().substring(1);
                    if (closure(s1,fds).contains(fl))
                    {

                         fds.add(new FD (fds.get(j).getLhs().substring(1, 2), fds.get(j).getRhs()));
                        fds.remove(j);
 
                    }
                }
                else if (fds.get(j).getLhs().charAt(1) == 3)
                {
                    s1 = fds.get(j).getLhs().substring(1);
                     if (closure(s1,fds).contains(fl))
                     {
                     fds.add(new FD (fds.get(j).getLhs().substring(1, 2), fds.get(j).getRhs()));
                     fds.add(new FD (fds.get(j).getLhs().substring(2, 3), fds.get(j).getRhs()));
                        fds.remove(j);
                     }
                }
                else if (fds.get(j).getLhs().charAt(1) == 4)
                {
                    s1 = fds.get(j).getLhs().substring(1);
                     if (closure(s1,fds).contains(fl))
                     {
                    fds.add(new FD (fds.get(j).getLhs().substring(1, 2), fds.get(j).getRhs()));
                    fds.add(new FD (fds.get(j).getLhs().substring(2, 3), fds.get(j).getRhs()));
                    fds.add(new FD (fds.get(j).getLhs().substring(3, 4), fds.get(j).getRhs()));
                        fds.remove(j);
                     }
                }
                
                else 
                {
                    return fds;
                }
            }
            
        }
        
      return fds;
    }
    public static void main(String[] args)
    {
        ArrayList<FD> fds = new ArrayList<FD>();
        FD fd = new FD("a", "BC");
        FD[] fdDecomposed = fd.decomposeRightHandSide();
        for (int i = 0; i < fdDecomposed.length; ++i)
        {
           fds.add( new FD(fdDecomposed[i].getLhs(), fdDecomposed[i].getRhs()));
        }
       
        fds.add(new FD("B", "C"));
        fds.add(new FD("AB", "B"));
        fds.add(new FD("C", "A"));
        System.out.println(fds);
        System.out.println(closure("b", fds));
        System.out.println(eliminateRedundantAttributes(fds));
        /* TEST it with 
        Let F1 = {1. A -> BC 
                  2. B -> C, 
                  3. AB -> D }. 
        Attribute B is extraneous in FD 3 AB -> D

        */
        
        
        /*
        F2 = { 1. AB -> C, 
               2. C -> A, 
               3. BC -> D, 
               4. ACD -> B, 
               5. D -> E, 
               6. D -> G, 
               7. BE -> C, 
               8. CG -> B,
               9. CG -> D, 
              10. CE -> A, 
              11. CE -> G}
        */
    }
}