<?php

use Illuminate\Database\Eloquent\Collection;

class OutcomesController extends \BaseController {


    /**
     * Show all Learning Outcomes and expected values
     *
     */
    public function index()
    {
        $title = "Learning Outcomes";
        $outcomes = Outcome::withTrashed()->orderBy('name', 'ASC')->get();
        $schools = School::orderBy('name', 'ASC')->get();
        // $semesters_ids = Session::get('semesters_ids');
        // $semesters = Semester::whereIn('id',$semesters_ids)->get();

        return View::make('local.managers.admins.learning-outcomes', compact('title', 'outcomes', 'schools'));
        //return View::make('local.managers.admins.learning-outcomes', compact('title', 'outcomes', 'schools','semesters'));
    }

    // TODO: Change to home page
    public function newIndex()
    {
        $title = "Learning Outcomes";
//        TODO: Check when semester doesnt exist or session is empty
        $selected_semester = Semester::find(Session::get('semesters_ids')[0]);
        $outcomes = Outcome::withTrashed()->where('deactivation_date', '>=', $selected_semester->start)->orWhere('deactivation_date', null)->orderBy('name', 'ASC')->get();
        $schools = School::orderBy('name', 'ASC')->get();

        return View::make('local.managers.admins.new-learning-outcomes', compact('title', 'outcomes', 'schools'));
    }

    public function show($id)
    {
        DB::disableQueryLog();
        $outcome = Outcome::find($id);

        $undergradResults=array("names"=>array(), "schools"=>array(), "achieved"=>array(), "attempted"=>array(), "successRate"=>array());
        $gradResults = array("names"=>array(), "schools"=>array(), "achieved"=>array(), "attempted"=>array(), "successRate"=>array());

        //Calculate performance for this outcome for each undergrad program
        $undergradPrograms = Program::where('is_graduate','=', 0)
            ->where(function($query)
            {
                if(Auth::user()->school_id)
                {
                    $query->where('school_id', Auth::user()->school_id);
                }
            })
            ->with('courses')
            ->orderBy('name', 'asc')->get();

        foreach($undergradPrograms as $program)
        {
            $undergradResults["names"][$program->id]=$program->name;
            $undergradResults["schools"][$program->id]=$program->school->name;
            $programAssessed=false;

            $undergradResults["attempted"][$program->id]=0;
            $undergradResults["achieved"][$program->id]=0;

            foreach($program->courses as $course)
            {
                $course_outcomes_achieved = json_decode($course->outcomes_achieved, true);
                $course_outcomes_attempted = json_decode($course->outcomes_attempted, true);

                $attemptedCriteriaCount=0;
                $achievedCriteriaCount=0;

                // If this outcome was evaluated
                if(
                    $course_outcomes_attempted
                    && array_key_exists($outcome->id, $course_outcomes_attempted)
                    && $course_outcomes_attempted[$outcome->id]!=0)
                {
                    // Count +1 for attempted and achieved in the program
                    $attemptedCriteriaCount+=$course_outcomes_attempted[$outcome->id];
                    $achievedCriteriaCount+=$course_outcomes_achieved[$outcome->id];
                    $programAssessed=true;

                    if($attemptedCriteriaCount>0  &&(float)$achievedCriteriaCount/$attemptedCriteriaCount*100 > $outcome->expected_outcome)
                    {
                        $undergradResults["achieved"][$program->id]+=1;
                    }
                    $undergradResults["attempted"][$program->id]+=1;
                }
            }

            // Calculate success rate for this program
            if($programAssessed && $undergradResults["attempted"][$program->id]>0)
                $undergradResults["successRate"][$program->id]= round((float)$undergradResults["achieved"][$program->id]/$undergradResults["attempted"][$program->id]*100, 2).'%';
            else
                $undergradResults["successRate"][$program->id]= 'N/M';
        }


        //Calculate performance for this outcome for each grad program
        $gradPrograms = Program::where('is_graduate','=', 1)
            ->where(function($query)
            {
                if(Auth::user()->school_id)
                {
                    $query->where('school_id', Auth::user()->school_id);
                }
            })
            ->with(array('courses'=>function($query)
            {
                $query->whereNotNull('outcomes_attempted');
            }))
            ->orderBy('name', 'asc')->get();

        foreach($gradPrograms as $program)
        {
            $gradResults["names"][$program->id]=$program->name;
            $gradResults["schools"][$program->id]=$program->school->name;

            $programAssessed=false;

            $gradResults["attempted"][$program->id]=0;
            $gradResults["achieved"][$program->id]=0;

            foreach($program->courses as $course)
            {
                $course_outcomes_achieved = json_decode($course->outcomes_achieved, true);
                $course_outcomes_attempted = json_decode($course->outcomes_attempted, true);

                $attemptedCriteriaCount=0;
                $achievedCriteriaCount=0;

                // If this outcome was evaluated
                if(
                    $course_outcomes_attempted
                    && array_key_exists($outcome->id, $course_outcomes_attempted)
                    && $course_outcomes_attempted[$outcome->id]!=0)
                {
                    // Count +1 for attempted and achieved in the program
                    $attemptedCriteriaCount+=$course_outcomes_attempted[$outcome->id];
                    $achievedCriteriaCount+=$course_outcomes_achieved[$outcome->id];
                    $programAssessed=true;

                    if($attemptedCriteriaCount>0  &&(float)$achievedCriteriaCount/$attemptedCriteriaCount*100 > $outcome->expected_outcome)
                    {
                        $gradResults["achieved"][$program->id]+=1;
                    }
                    $gradResults["attempted"][$program->id]+=1;
                }
            }

            // Calculate success rate for this program
            if($programAssessed && $gradResults["attempted"][$program->id]>0)
                $gradResults["successRate"][$program->id]= round((float)$gradResults["achieved"][$program->id]/$gradResults["attempted"][$program->id]*100, 2).'%';
            else
                $gradResults["successRate"][$program->id]= 'N/M';
        }

        $title = "Outcome Results: ".$outcome->name;

        return View::make('local.managers.admins.learning-outcome', compact('title', 'outcome', 'undergradResults', 'gradResults'));
    }

    // TODO: Clean up and verify relationships are correct
    public function newShow($id)
    {
//        DB::disableQueryLog();
//        $outcome = null;
        if ($id === 'all') {
            $outcome = Outcome::with('objectives.criteria')->get();
            $title = 'All Outcomes';
            $criteria = $outcome->reduce(function($carry, $outcome) {
                return $carry->merge($outcome->criteria);
            }, Collection::make([]));
            $report_link = URL::action('OutcomesController@newReportAll');
        } else {
            $outcome = Outcome::with(['objectives.criteria'])->find($id);
            $title = $outcome->name;
            $criteria = $outcome->criteria->load('rubrics');
            $report_link = URL::action('OutcomesController@newReport', ['id' => $outcome->id]);
        }

//        $objectives = $outcome->objectives;
//        var_dump(get_class_methods($criteria));
//        var_dump($criteria);
        $rubrics = $criteria->reduce(function($carry, $crit) {
            return $carry->merge($crit->rubrics);
        }, Collection::make([]))->load('activities');
        $activities = $rubrics->reduce(function($carry, $rubric) {
            return $carry->merge($rubric->activities);
        }, Collection::make([]));
        $courses = $activities->reduce(function($carry, $activity) {
            if ($activity->course !== null) {
                $carry->push($activity->course);
            }
            return $carry;
        }, Collection::make([]));
        $activities = $activities->filter(function($activity) {
            return ($activity->course === null);
        });

//        var_dump(DB::getQueryLog());
        return View::make('local.managers.admins.new-learning-outcome', compact('title', 'outcome', 'courses', 'activities', 'report_link'));
    }

    public function newReport($id)
    {
        $outcome = Outcome::find($id);
        $objectives = $outcome->objectives;
        $criteria = $outcome->criteria;
        $programs = $objectives->map(function ($objective) { return $objective->program; })
            ->merge($criteria->map(function ($criteria) { return $criteria->program; }))
            ->filter(function ($program) { return $program->users->contains(Auth::user()); });
        $title = $outcome->name . ' Report';


        return View::make('local.managers.admins.new-report', compact('title', 'outcome', 'objectives'));

    }

    public function newReportAll()
    {
        $outcomes = Outcome::with('objectives')->get();
        $title = 'All Outcomes Report';

        return View::make('local.managers.admins.new-report-all', compact('title', 'outcomes'));

    }

    public function update()
    {
        $outcomeArray = json_decode(Input::get('outcomeArray'), true);
        Session::flash('status', 'success');
        Session::flash('message', 'Learning Outcomes updated.');

        foreach ($outcomeArray as $outcomeObject)
        {


            $validator = Validator::make(
                array(
                    'name' => $outcomeObject['name'],
                    'definition' => $outcomeObject['definition'],
                    'expected_outcome' => $outcomeObject['expected_outcome']
                ),
                array(
                    'name' => 'required',
                    'definition' => 'required',
                    'expected_outcome' => 'required|numeric'
                )
            );

            if(!$validator->fails())
            {
                try
                {
                    $outcome = Outcome::withTrashed()
                        ->where('id','=', $outcomeObject['id'])
                        ->firstOrFail();
                    $outcome->name = $outcomeObject['name'];
                    $outcome->definition = $outcomeObject['definition'];
                    $outcome->expected_outcome = $outcomeObject['expected_outcome'];
                    $outcome->save();

                    // If delete is 1, and outcome isn't already trashed, delete
                    if($outcomeObject['delete']==1 && !$outcome->trashed())
                        $outcome->delete();
                    // If delete is 0, and outcome is already trashed, restore
                    elseif($outcomeObject['delete']==0 && $outcome->trashed())
                        $outcome->restore();
                }

                catch(Exception $e)
                {

                    Session::flash('message', $e->getMessage());
                }
            }
            else
            {
                /** Prepare error message */
                $message = 'Error(s) updating the Learning Outcomes: <ul>';

                foreach ($validator->messages()->all('<li>:message</li>') as $validationError)
                {
                    $message.=$validationError;
                }

                $message.='</ul>';

                /** Send error message and old data */
                Session::flash('status', 'danger');
                Session::flash('message', $message);
                return;
            }
        }

        return;
    }

    /**
    *Copy of update(), but also updates activation_date, deactivation_date and level
    */
    public function updateMore()
    {
        $outcomeArray = json_decode(Input::get('outcomeArray'), true);
        Session::flash('status', 'success');
        Session::flash('message', 'Learning Outcomes updated.');

        foreach ($outcomeArray as $outcomeObject)
        {


            $validator = Validator::make(
                array(
                    'name' => $outcomeObject['name'],
                    'definition' => $outcomeObject['definition'],
                    'expected_outcome' => $outcomeObject['expected_outcome']
                    // TODO- validar los otros 3 valores
                ),
                array(
                    'name' => 'required',
                    'definition' => 'required',
                    'expected_outcome' => 'required|numeric'
                    // TODO- los requisitos de los otros 3 valores
                )
            );

            if(!$validator->fails())
            {
                try
                {
                    $outcome = Outcome::withTrashed()
                        ->where('id','=', $outcomeObject['id'])
                        ->firstOrFail();
                    $outcome->name = $outcomeObject['name'];
                    $outcome->definition = $outcomeObject['definition'];
                    $outcome->expected_outcome = $outcomeObject['expected_outcome'];
                    $outcome->activation_date = $outcomeObject['activation_date'];
                    $outcome->deactivation_date = $outcomeObject['deactivation_date'];
                    $outcome->level = $outcomeObject['level'];
                    $outcome->save();

                    // If delete is 1, and outcome isn't already trashed, delete
                    if($outcomeObject['delete']==1 && !$outcome->trashed())
                        $outcome->delete();
                    // If delete is 0, and outcome is already trashed, restore
                    elseif($outcomeObject['delete']==0 && $outcome->trashed())
                        $outcome->restore();
                }

                catch(Exception $e)
                {

                    Session::flash('message', $e->getMessage());
                }
            }
            else
            {
                /** Prepare error message */
                $message = 'Error(s) updating the Learning Outcomes: <ul>';

                foreach ($validator->messages()->all('<li>:message</li>') as $validationError)
                {
                    $message.=$validationError;
                }

                $message.='</ul>';

                /** Send error message and old data */
                Session::flash('status', 'danger');
                Session::flash('message', $message);
                return;
            }
        }

        return;
    }

    public function fetchCriteria()
    {

        if(Input::get('filter'))
        {
            switch (Input::get('filter'))
            {
                case 'all':
                    return Outcome::find(Input::get('id'))->criteria;
                    break;

                case 'school':
                    // If scoord
                    if(Auth::user()->role == '2')
                    {

                        // Fetch all the programs whose school is the user's
                        $program_ids = DB::table('programs')->where('school_id', Auth::user()->school_id)->lists('id');

                        // Return all criteria belonging to any of those programs
                        return Criterion::
                            where('outcome_id', Input::get('id'))
                            ->whereIn('program_id', $program_ids)
                            ->orderBy('name', 'ASC')
                            ->get();

                    }

                    // If pcoord
                    else
                    {

                        // Fetch all the programs from the user's school;
                        $program_ids = DB::table('programs')->where('school_id', Auth::user()->programs[0]->school->id)->lists('id');

                        return Criterion::
                            where('outcome_id', Input::get('id'))
                            ->whereIn('program_id', $program_ids)
                            ->orderBy('name', 'ASC')
                            ->get();
                    }

                    break;

                case 'program':
                    return Criterion::
                        where('outcome_id', Input::get('id'))
                        ->whereIn('program_id', Auth::user()->programs->lists('id'))
                        ->orderBy('name', 'ASC')
                        ->get();
                    break;

                default:
                    return Outcome::find(Input::get('id'))->criteria;
                    break;
            }
        }
        else
        {
            return Outcome::find(Input::get('id'))->criteria;
        }
    }

    /**
     * Create a new learning outcome.
     */
    public function create()
    {
        /** Validation rules */
        $validator = Validator::make(
            array(
                'name' => Input::get('name'),
                'definition' => Input::get('definition')
            ),
            array(
                'name' => 'required|unique:outcomes',
                'definition' => 'required|min:10'
            )
        );

        /** If validation fails */
        if ($validator->fails())
        {
            /** Prepare error message */
            $message = '<p>Error(s) creating a new Learning Outcome</p><ul>';

            foreach ($validator->messages()->all('<li>:message</li>') as $validationError)
            {
                $message.=$validationError;
            }

            $message.='</ul>';

            /** Send error message and old data */
            Session::flash('status', 'warning');
            Session::flash('message', $message);
            return Redirect::to('learning-outcomes')->withInput();
        }
        else
        {
            /** Instantiate new outcome */
            $outcome = new Outcome;
            $outcome->name= Input::get('name');
            $outcome->definition = Input::get('definition');

            /** If outcome is saved, send success message */
            if($outcome->save())
            {
                Session::flash('status', 'success');
                Session::flash('message', '<p>Learning Outcome added.</p>');
                return Redirect::to('learning-outcomes');
            }

            /** If saving fails, send error message and old data */
            else
            {
                Session::flash('status', 'warning');
                Session::flash('message', '<p>Error adding Learning Outcome. Please try again later.</p>');
                return Redirect::to('learning-outcomes')->withInput();
            }
        }
    }

    public function fetchOutcome()
    {
        $id = Input::get('id');

        $outcome = Outcome::find($id);

        $outcome->criteria;

        return array
        (
            'outcome' => $outcome
        );
    }

    public function managerAssessmentReports()
    {
        $outcomes = Outcome::select(array('id', 'name', 'expected_outcome'))->orderBy('name', 'ASC')->get();

        switch (Auth::user()->role) {
            case 1:
                $title = "Campus Assessment Reports";
                return View::make('local.managers.admins.assessment_reports', compact('title', 'outcomes'));
                break;
            case 2:
                $title = "School Assessment Reports";
                return View::make('local.managers.sCoords.assessment_reports', compact('title', 'outcomes'));
                break;
            case 3:
                $title = "Program Assessment Reports";
                $programs  = Auth::user()->programs;
                return View::make('local.managers.pCoords.assessment_reports', compact('title', 'outcomes', 'programs'));
                break;
            default:
                App::abort('404');
                break;
        }

    }

    /**
     * Campus Assessment Reports
     */
    public function assessmentReport($outcome_id)
    {
        $outcome = Outcome::find($outcome_id);

        if(!$outcome)
            App::abort('404');
        $title = "Assessment Report: ".$outcome->name;


        $schools = School::
            has('courses')
            ->with(array('programs'=>function($query) use($outcome_id){
                $query
                ->has('courses')
                ->with(array('courses'=>function($query2) use($outcome_id){
                    $query2
                    ->has('activities')
                    ->whereNotNull('outcomes_attempted')
                    // ->where('outcomes_attempted', 'NOT LIKE', '%"'.$outcome_id.'":0%')
                    ->whereIn('semester_id', Session::get('semesters_ids'))
                    ->groupBy(array('code', 'number'));
                }));
            }))
         ->get();

        return View::make('local.managers.admins.assessment_report', compact('title', 'outcome', 'schools'));
    }

    // TODO: Change later
    public function newAssessmentReport($outcome_id)
    {
        $outcome = Outcome::find($outcome_id);

        if(!$outcome)
            App::abort('404');
        $title = "Assessment Report: ".$outcome->name;

        $schools = School::
        has('courses')
            ->with(array('programs'=>function($query) use($outcome_id){
                $query
                    ->has('courses')
                    ->with(array('courses'=>function($query2) use($outcome_id){
                        $query2
                            ->has('activities')
                            ->whereNotNull('outcomes_attempted')
                            // ->where('outcomes_attempted', 'NOT LIKE', '%"'.$outcome_id.'":0%')
                            ->whereIn('semester_id', Session::get('semesters_ids'))
                            ->groupBy(array('code', 'number'));
                    }));
            }))
            ->get();

        return View::make('local.managers.admins.assessment_report', compact('title', 'outcome', 'schools'));
    }

    /**
     * School Assessment Reports
     */
    public function schoolAssessmentReport($outcome_id)
    {
        $outcome = Outcome::find($outcome_id);

        if(!$outcome)
            App::abort('404');
        $title = "Assessment Report: ".$outcome->name;


        $school = School::
            where('id', Auth::user()->school_id)
            ->has('courses')
            ->with(array('programs'=>function($query){
            $query
            ->has('courses')
            ->with(array('courses'=>function($query2){
                $query2
                ->has('activities')
                ->whereNotNull('outcomes_attempted')
                ->whereIn('semester_id', Session::get('semesters_ids'))
                ->groupBy(array('code', 'number'));
            }));
         }))
         ->first();

        return View::make('local.managers.sCoords.assessment_report', compact('title', 'outcome', 'school'));
    }

    /**
     *    Program Assessment Reports
     */
    public function programAssessmentReport($outcome_id, $program_id)
    {
        $outcome = Outcome::find($outcome_id);

        if(!$outcome)
            App::abort('404');
        $title = "Assessment Report: ".$outcome->name;


        $program = Program::
            where('id', $program_id)
            ->has('courses')
            ->with(array('courses'=>function($query){
                $query
                ->has('activities')
                ->whereNotNull('outcomes_attempted')
                ->whereIn('semester_id', Session::get('semesters_ids'))
                ->groupBy(array('code', 'number'));
            }))
            ->first();

        return View::make('local.managers.pCoords.assessment_report', compact('title', 'outcome', 'program'));
    }


    public function professorAssessmentReports()
    {
        $outcomes = Outcome::select(array('id', 'name', 'expected_outcome'))->orderBy('name', 'ASC')->get();
        $title = "My Courses' Assessment Reports";

        return View::make('local.professors.assessment_reports', compact('title', 'outcomes'));

    }


    // Report for a single professor with a single learning outcome
    public function professorAssessmentReport($outcome_id)
    {
        $outcome = Outcome::find($outcome_id);

        if(!$outcome)
            App::abort('404');
        $title = "My Courses' Assessment Report: ".$outcome->name;


        $courses = Course::
            where('user_id', Auth::user()->id)
            ->has('activities')
            ->whereNotNull('outcomes_attempted')
            ->whereIn('semester_id', Session::get('semesters_ids'))
            ->groupBy(array('code', 'number'))
            ->get();

        return View::make('local.professors.assessment_report', compact('title', 'outcome', 'courses'));
    }
}
