/**************************************************************************
 * All classes together
 *************************************************************************/
/**************************************************************************
 * The course Catalog class
 * Load a course catalog
 *************************************************************************/
class CatalogCourse 
{
    String type;                                        //instance fields 
    String courseId;                                    //each course will have these fields
    String description;
    String instructor;    
    int    credit;
    double price;

    static final double pricePerCredit = 1199.95;    

    //constructors
    public CatalogCourse(String type, String courseId, String desc, String instructor)
    {
        this.type        = type;
        this.courseId    = courseId;
        this.description = desc;
        this.instructor  = instructor;
    }
    public CatalogCourse(String type, String courseId, String desc, String instructor, int credit)
    {
        this(type, courseId, desc, instructor);
        this.credit = credit;
        this.price  = credit * pricePerCredit;		
    }

    //load catalog courses
    //return an array of catalog courses
    public static CatalogCourse[] loadCourses()
    {
        CatalogCourse[] cat_course = new CatalogCourse[50];

        cat_course[0]  = new CatalogCourse("HS", "HS-001", "English I","Mr English");
        cat_course[1]  = new CatalogCourse("HS", "HS-002", "English II", "Ms English");
        cat_course[2]  = new CatalogCourse("HS", "HS-003", "Writing", "Mr Smith");
        cat_course[3]  = new CatalogCourse("HS", "HS-004", "Communication", "Ms Brown");
        cat_course[4]  = new CatalogCourse("HS", "HS-005", "Literature", "Mr Murphy");
        cat_course[5]  = new CatalogCourse("HS", "HS-006", "Spanish", "Ms Espaniola");
        cat_course[6]  = new CatalogCourse("HS", "HS-007", "French", "Mr Francais");
        cat_course[7]  = new CatalogCourse("HS", "HS-008", "German", "Ms Deutsch");
        cat_course[8]  = new CatalogCourse("HS", "HS-009", "Italian", "Mr Italiano");
        cat_course[9]  = new CatalogCourse("HS", "HS-010", "Latin", "Ms Latina");
        cat_course[10] = new CatalogCourse("HS", "HS-011", "Math", "Mr Smart");
        cat_course[11] = new CatalogCourse("HS", "HS-012", "Algebra", "Ms Algo");
        cat_course[12] = new CatalogCourse("HS", "HS-013", "Geometry", "Mr Sphere");
        cat_course[13] = new CatalogCourse("HS", "HS-014", "Statistics", "Ms Stat");
        cat_course[14] = new CatalogCourse("HS", "HS-015", "Calculus", "Mr Cane");
        cat_course[15] = new CatalogCourse("HS", "HS-016", "Biology", "Ms Bailey");
        cat_course[16] = new CatalogCourse("HS", "HS-017", "Chemistry", "Mr Silver");
        cat_course[17] = new CatalogCourse("HS", "HS-018", "Physics", "Ms Lenora");
        cat_course[18] = new CatalogCourse("HS", "HS-019", "Psychology", "Mr Shrink");
        cat_course[19] = new CatalogCourse("HS", "HS-020", "Economics", "Ms Richards");
        cat_course[20] = new CatalogCourse("HS", "HS-021", "Computers", "Mr Compute");
        cat_course[21] = new CatalogCourse("HS", "HS-022", "Web Prog", "Ms Webster");
        cat_course[22] = new CatalogCourse("HS", "HS-023", "App Dev", "Mr Apple");
        cat_course[23] = new CatalogCourse("HS", "HS-024", "Animation", "Ms Anime");
        cat_course[24] = new CatalogCourse("HS", "HS-025", "Graphics", "Mr Graphite");
		
        cat_course[25] = new CatalogCourse("COL", "CL-001", "English", "Prof English", 3);
        cat_course[26] = new CatalogCourse("COL", "CL-002", "Arts", "Prof Artist", 3);
        cat_course[27] = new CatalogCourse("COL", "CL-003", "Biology I", "Prof Bailey", 4);
        cat_course[28] = new CatalogCourse("COL", "CL-004", "Biology II", "Prof Bailey", 4);
        cat_course[29] = new CatalogCourse("COL", "CL-005", "Biochemistry", "Prof Mixed", 4);
        cat_course[30] = new CatalogCourse("COL", "CL-006", "Chemistry I", "Prof Gold", 4);
        cat_course[31] = new CatalogCourse("COL", "CL-007", "Chemistry II", "Prof Gold", 4);
        cat_course[32] = new CatalogCourse("COL", "CL-008", "Languages", "Prof Classico", 3);
        cat_course[33] = new CatalogCourse("COL", "CL-009", "Literature", "Prof Little", 3);
        cat_course[34] = new CatalogCourse("COL", "CL-010", "Communication", "Prof Culver", 3);
        cat_course[35] = new CatalogCourse("COL", "CL-011", "CS I", "Prof Compute", 4);
        cat_course[36] = new CatalogCourse("COL", "CL-012", "CS II", "Prof Compute", 4);
        cat_course[37] = new CatalogCourse("COL", "CL-013", "Data Struct", "Prof Struct", 4);
        cat_course[38] = new CatalogCourse("COL", "CL-014", "Java", "Prof Sultan", 4);
        cat_course[39] = new CatalogCourse("COL", "CL-015", "Web Dev", "Prof Sultan", 4);
        cat_course[40] = new CatalogCourse("COL", "CL-016", "Spanish", "Prof Espaniol", 3);
        cat_course[41] = new CatalogCourse("COL", "CL-017", "French", "Prof Francais", 3);
        cat_course[42] = new CatalogCourse("COL", "CL-018", "German", "Prof Deutsch", 3);
        cat_course[43] = new CatalogCourse("COL", "CL-019", "Italian", "Prof Italiano", 3);
        cat_course[44] = new CatalogCourse("COL", "CL-020", "Latin", "Prof Latina", 3);
        cat_course[45] = new CatalogCourse("COL", "CL-021", "Math", "Prof Smart", 20);
        cat_course[46] = new CatalogCourse("COL", "CL-022", "Pre-Med", "Prof Perry", 25);
        cat_course[47] = new CatalogCourse("COL", "CL-023", "Accounting", "Prof Ace", 23);
        cat_course[48] = new CatalogCourse("COL", "CL-024", "Bus&Fin", "Prof Busy", 22);
        cat_course[49] = new CatalogCourse("COL", "CL-025", "Special", "Prof Stuart", 20);
        
        return(cat_course);
    }

    public static void main(String[] args)
    {    
        CatalogCourse[ ] cat_course = loadCourses();				                //load the course catalog

        for(CatalogCourse c : cat_course)
            System.out.printf("%4s %7s %-14s %-14s %3d %8.2f \n",c.type,c.courseId,c.description,c.instructor,c.credit,c.price);
    }
}

/**************************************************************************
 * The Course class
 *************************************************************************/
class Course 
{
    private String courseId;
    private String description;
    private String instructor;    
    private int    credit;
    private int    grade;

    //constructors
    public Course(String courseId, String desc, String instructor)
    {
        this.courseId    = courseId;
        this.description = desc;
        this.instructor  = instructor;
    }
    public Course(String courseId, String desc, String instructor, int credit)
    {
        this(courseId, desc, instructor);
        this.credit = credit;           
    }

    //getters and setters
    public String getCourseId() {
        return courseId;
    }
    public void setCourseId(String id) {
        this.courseId = id;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getInstructor() {
        return instructor;
    }
    public void setInstructor(String instructor) {
        this.instructor = instructor;
    }
    public int getCredit() {
        return credit;
    }
    public void setCredit(int credit) {
        this.credit = credit;
    }
    public int getGrade() {
        return grade;
    }
    public void setGrade(int grade) {
        this.grade = grade;
    }

    //toString() method
    public String toString()
    {
        String data = "Course: " + courseId  + "/" + description + 
                      "\tInstructor: " + instructor;
 
        data += (credit > 0) ? "\tCredit: " + credit : "";         
        data += (grade  > 0) ? " Grade: "   + grade  : ""; 
         
        return (data);
    }
}

/**************************************************************************
 * Abstract Superclass Student
 *************************************************************************/
abstract class Student 
{
        //the static fields
        private static final String LOCALE = "New York";
        private static   int nextStudentID = 1000;
            
        //the instance fields
        private int    studentID;
        private String firstName, lastName, address, city, state, email = "";

        protected Course[] courses = new Course[40];

        //the constructors
        Student(String firstName, String lastName)
        {
            this.firstName = firstName;
            this.lastName  = lastName;
            this.studentID = ++nextStudentID;
        }
        Student(String firstName, String lastName, String address, String city, String state, String email)
        {
            this(firstName,lastName);  
            this.address = address;
            this.city = city;
            this.state = state;
            this.email = email;
        }

        //methods - will be overriden in subclasses using polymorphism 

        void registerCourse(String id, String desc, String instructor) {}                       //method stub
        void registerCourse(String id, String desc, String instructor, int credit) {}           //method stub 
        void registerCourse(CatalogCourse course) {}                                            //method stub

        abstract boolean isGraduateEligible();                                              	//abstract method

        //add a course to the courses array
        void addCourse(Course c)
        { 
            int i=0;
            while(courses[i] != null)           //if array element is occupied
                i++;                            //next
            this.courses[i] = c;
        }                

        //grade a course
        void gradeCourse(String id, int grade)
        {
            Course c = findCourseById(id);
            c.setGrade(grade);
        }

        //find a course by courseId
        private Course findCourseById(String id)
        {
            Course course = null;

            for (Course c : courses)
            {
                String courseId = c.getCourseId();
                if (c != null && courseId.equals(id))
                {
                    course = c;
                    break;              //once found, no need to continue
                }
            }
            return course;                         
        }

        //the getter methods
        int getStudentID()
        {
            return(studentID);
        }           
        String getFirstName()
        {
            return(firstName);
        }
        String getLastName()
        {
            return(lastName);
        }
        String getFullName()
        {
            return(firstName + " " + lastName);  
        }
        String getAddress()
        {
            return(address);
        }
        String getCity()
        {
            return(city);
        }
        String getState()
        {
            return(state);
        }    
        String getEmail()
        {
            return(email);
        }

        //the setter methods
        void setFirstName(String fname)
        {
            firstName = fname;
        }
        void setLastName(String lname)
        {
            lastName = lname;
        }
        void setAddress(String address)
        {
            this.address = address;
        }
        void setCity(String city)
        {
            this.city = city;
        }
        void setState(String state)
        {
            this.state = state;
        }
        void setEmail(String email)
        {
            this.email = email;
        }
            
        //the toString() method used to print the objects
        public String toString ()
        {
            int coursesTaken=0;
            while(courses[coursesTaken] != null)
                coursesTaken++;

            String data = "Student Number: " + studentID     + "\n" +
                          "Student Name..: " + getFullName() + "\n" +
                          "Address.......: " + address       + "\t" + city + "\t" + state + "\n" + 
                          "Email Addr....: " + email         + "\n" +
                          "Courses Taken.: " + coursesTaken  + "\n";
                
            for (Course c : courses)
                if (c != null) 
                    data += "\t" + c + "\n";
                
            return (data);
        }
}

/**************************************************************************
 * Subclass College Student
 *************************************************************************/
class StudentCol extends Student
{
    private static final int minCreditsToGraduate = 122;
    private static final int passingGrade = 70;

    //the constructors
    StudentCol(String firstName, String lastName)
    {
        super(firstName, lastName);
    }
    StudentCol(String firstName, String lastName, String address, String city, String state, String email)
    {
        super(firstName, lastName, address, city, state, email);
    }

    //Override superclass methods

    void registerCourse(String id, String desc, String instructor, int credit)          //course info is arbitrary
    {
        Course c = new Course(id, desc, instructor, credit);
        addCourse(c);           
    } 
    void registerCourse(CatalogCourse co)                                               //course info is from catalog									
    {
        Course c = new Course(co.courseId, co.description, co.instructor, co.credit);
        addCourse(c);           
    }

    boolean isGraduateEligible()
    {
        int creditCount = 0;
 
        for (Course c : courses)
            if (c != null && c.getGrade() >= passingGrade)
                creditCount += c.getCredit();
        
        return(creditCount >= minCreditsToGraduate ? true : false);
    }

    public String toString ()
    {
        String data = "College Student... \n" + super.toString();               
        return (data);
    }
}

/**************************************************************************
 * Subclass High School Student
 *************************************************************************/
class StudentHS extends Student
{
    private static final int minCoursesToGraduate = 22;
    private static final int passingGrade = 65;

    //the constructors
    StudentHS(String firstName, String lastName)
    {
        super(firstName, lastName);
    }
    StudentHS(String firstName, String lastName, String address, String city, String state, String email)
    {
        super(firstName, lastName, address, city, state, email);
    }

    //Override superclass methods

    void registerCourse(String id, String desc, String instructor)                      //course info is arbitrary
    {
        Course c = new Course(id, desc, instructor);
        addCourse(c);       
    }

    void registerCourse(CatalogCourse co)                                               //course info is from catalog
    {
        Course c = new Course(co.courseId, co.description, co.instructor);
        addCourse(c);           
    }

    boolean isGraduateEligible()
    {       
        int courseCount = 0;
 
        for (Course c : courses)
            if (c != null && c.getGrade() >= passingGrade)
                courseCount += 1;
        
        return(courseCount >= minCoursesToGraduate ? true : false);
    }

    public String toString ()
    {
        String data = "High School Student... \n" + super.toString();           
        return (data);
    }
}

/**************************************************************************
 * The Student test class
 *************************************************************************/
public class StudentTest
{
    public static void main(String[] args)
    {
		//load the course catalog
		CatalogCourse[] cat_course = CatalogCourse.loadCourses();
		
		//Polymorphism  
        //Notice I am storing all types of students in the same array

        Student[] student = new Student[100];
                                
        student[0] = new StudentHS("Tom","Jones");
        student[1] = new StudentCol("Fred","Smith");
        student[2] = new StudentCol("Bill","Anderson","10 Elm St.","Buffalo","NY","banderson@blah.com");
        student[3] = new StudentCol("Ellen","Wilson","13 4th Ave.","Boston","MA","ewilson@blah.edu");
        student[4] = new StudentHS("Mary","Holt","1 Front St.","Edison","NJ","mholt@blah.org");
        student[5] = new StudentHS("Jenn","Lu","1 Back St.","Brooklyn","NY","jlu@gmail.com");

        //use setters to complete the information for student[0] and [1]
        student[0].setAddress("88 12th St.");
        student[0].setCity("Boise");
        student[0].setState("ID");
        student[0].setEmail("fsmith@blahblah.com");

        student[1].setAddress("15 Oak Dr.");
        student[1].setCity("Newark");
        student[1].setState("NJ");
        student[1].setEmail("tjones@blahblah.edu");

        //Polymorphism - Notice the "right" registerCourse() method will be called

        //Adding/registering courses to College student
        student[2].registerCourse("CX-010","Java","Sam Sultan",3);              //course info is arbitrary
        student[2].registerCourse(cat_course[26]);                              //course info from the catalog

        student[3].registerCourse("CX-010","Java","Sam Sultan",4);			   
        student[3].registerCourse(cat_course[39]);						
        student[3].registerCourse("CX-011","SQL", "bbb bbbb",  10);
        student[3].registerCourse("CX-015","PHP", "ccc cccc",  15);
        student[3].registerCourse("CX-021","XML", "ddd dddd",  15);
        student[3].registerCourse("CX-032","HTML","eee eeee",  90);
                
        //Adding/registering courses to HS student
        student[4].registerCourse("HSX-001","English-1","Mrs. Browne"); 
        student[4].registerCourse("HSX-011","Biology ", "B. bbbbbbbb");
        student[4].registerCourse("HSX-123","Math-1  ", "C. cccccccc");
        student[4].registerCourse("HSX-124","French-1", "D. dddddddd");
        student[4].registerCourse(cat_course[13]);
        student[4].registerCourse("HSX-125","Chemistry","E. eeeeeeee");
        student[4].registerCourse("HSX-126","English-2","F. ffffffff");

        //Adding/registering many courses to HS student using a loop
        student[5].registerCourse("HSX-001","English-1","Mr. Smith");
        for (int i=2; i<=24; i++)
            student[5].registerCourse("HSX-0"+i , "Subject-"+i , "teacher-"+i);
                
        //Grading courses
        student[2].gradeCourse("CX-010",75);

        student[3].gradeCourse("CX-010",95);
        student[3].gradeCourse("CX-011",92);
        student[3].gradeCourse("CL-015",92);
        student[3].gradeCourse("CX-015",96);
        student[3].gradeCourse("CX-032",93);

        student[4].gradeCourse("HSX-001",85);
        student[4].gradeCourse("HSX-011",82);
        student[4].gradeCourse("HSX-126",83);

        //Grading many courses using a loop
        student[5].gradeCourse("HSX-001",92);
        for (int i=2; i<=24; i++)
            student[5].gradeCourse("HSX-0"+i , 86);
                    
        //looping through all students (College and High School)
        //the isGraduateEligible() method is polymorphic 
        //the "right" version will be called depending on the student

        for (int i=0; i<student.length; i++)
            if (student[i] != null)
            {
                boolean isGraduate = student[i].isGraduateEligible();  

                System.out.print(student[i]);                           //print content of entire object
                System.out.println("Graduating....? " + isGraduate);    //print whether eligible for graduation
                System.out.println();                               
            }
    }               
}