<?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)
    {
    	$outcome = Outcome::find($id);
        $selected_semesters = Semester::find(Session::get('semesters_ids'));
        $programs=$outcome->programs_attempted($selected_semesters);
        
        $undergradResults=array("names"=>array(), "schools"=>array(), "achieved"=>array(), "attempted"=>array(), "successRate"=>array());
        $gradResults=array("names"=>array(), "schools"=>array(), "achieved"=>array(), "attempted"=>array(), "successRate"=>array());
        foreach($programs as $program_id)
        {
 //        	var_dump($program_id);
//         	exit();
        	$program = Program::where('id','=',$program_id->id)->first();
        	$school = School::where('id','=',$program->school_id)->first();
        	if($program->is_graduate)
        	{
        		$gradResults['names'][]=$program->name;
        		$gradResults['schools'][]=$school->name;
        		$attempted=$program->attempted_criteria_by_outcome($id, $selected_semesters);
        		$gradResults['attempted'][]=$attempted;
        		$achieved=$program->achieved_criteria_by_outcome($id, $selected_semesters);
        		$gradResults['achieved'][]=$achieved;
        		$gradResults['successRate'][]=sprintf("%.2f",100*$achieved/$attempted); 		
        		
        	}
        	else
        	{
        		$undergradResults['names'][]=$program->name;
        		$undergradResults['schools'][]=$school->name;
        		$attempted=$program->attempted_criteria_by_outcome($id,$selected_semesters);
        		$undergradResults['attempted'][]=$attempted;
        		$achieved=$program->achieved_criteria_by_outcome($id,$selected_semesters);
        		$undergradResults['achieved'][]=$achieved;
        		$undergradResults['successRate'][]=sprintf("%.2f",100*$achieved/$attempted); 		
        	}
        
        }
           	
	   	$title = "Outcome Results: ".$outcome->name;
    	
        
//  		$undergradResults["successRate"]
	
        return View::make('local.managers.admins.learning-outcome_new', compact('title', 'outcome', 'undergradResults', 'gradResults'));
    }

//     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'));
    }
}