<?php
namespace Drupal\asc_courses;

// use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
// use Drush\Commands\DrushCommands;
use \Drupal\Core\Database\Database;
use \Drupal\Core\Config;

class AscCoursesApi {
  public $debug = 0;
  protected $consumer_key;
  protected $consumer_secret;
  public $config;
  public $soip_constant_name;
  public $environment;
  public $base_url;
  public $access_token;
  public $access_token_data;
  public $resolve_host;
  public $db;


  /**
   * {@inheritdoc}
   */
  public function __construct($config = null, $db = null, $environment = '') {
    // Get settings
    if (!empty($config)) {
      $this->config = $config;
    }
    else {
      $this->config = $config = \Drupal::service('config.factory')->get('asc_courses.settings');
    }
    
    if ($this->debug) echo "\nAPI connector class instantiated\n";

    // Get environment if not overridden
    if(empty($environment)) {
      if ($this->debug) echo "Environment argument was empty. Reading it from configuration.\n";
      $environment = $this->config->get('asc_courses.eip_environment');
    }
    if ($this->debug) echo "Environment: " . $environment . "\n";

    // Get database connection
    if(empty($db)) {
      $this->db = \Drupal::database();
    }
    // HARD CODED VALUES
    if ($environment == 'prod') {
      $this->environment = $environment;
      $this->base_url = "https://apig.eip.osu.edu/";
      $this->consumer_key = $config->get('asc_courses.prod_consumer_key');
      $this->consumer_secret = $config->get('asc_courses.prod_consumer_secret');
      $this->soip_constant_name = "PANTHEON_SOIP_EIP_PROD";
    }
    else {
      $this->environment = $environment;
      $this->base_url = "https://apig-qa.eip.osu.edu/";
      $this->consumer_key = $config->get('asc_courses.qa_consumer_key');
      $this->consumer_secret = $config->get('asc_courses.qa_consumer_secret');
      $this->soip_constant_name = "PANTHEON_SOIP_EIP";  
    }

    if(isset($_ENV['PANTHEON_ENVIRONMENT']) && $_ENV['PANTHEON_ENVIRONMENT'] != "lando") {
      if ($this->debug) echo "Pantheon environment: " . $_ENV['PANTHEON_ENVIRONMENT'] . "\n";
      $host = parse_url($this->base_url, PHP_URL_HOST);
      if ($this->debug) echo "host: $host\n";
      $localhost = "127.0.0.1";
      $this->resolve_host = array(sprintf("%s:%d:%s", $host, constant($this->soip_constant_name), $localhost));
      if ($this->debug) echo "\n resolve_host : " . implode($this->resolve_host) . "\n";
      // error_log("resolve_host : " . implode($this->resolve_host));
    }

    if ($this->debug) echo "\n\n";
  }

  /**
   * Return an access token if possible
   */
  public function getAccessToken() {
    if($this->debug) echo "============ getAccessToken =============\n";
    $now = time();
    if($this->debug) echo "Current time: " . date("Y-m-d h:i:s", $now) . "\n";

    // First check object variables
    if(!empty($this->access_token_data) 
       && (($this->access_token_data->expiration - $now) > 30)) 
    {
      if($this->debug) echo "Object variables were set and not stale\n";
      $this->access_token = $this->access_token_data->access_token;        
    }
    else {
      // fetch configuration
      $env_access_token_setting = 'asc_courses.' . $this->environment . '_access_token';
      if($this->debug) echo "env_access_token_setting: $env_access_token_setting\n";
      $access_token_data = unserialize($this->config->get($env_access_token_setting));
      if($this->debug) echo "Config access token: " . print_r($access_token_data, true) . "\n";

      if(!empty($access_token_data)
         && (($access_token_data->expiration - $now) > 30)) 
      {
        if($this->debug) echo "Config token was available and not stale.\n";
        $this->access_token_data = $access_token_data;
        $this->access_token = $access_token_data->access_token;
      }
      else {
        if($this->debug) echo "Config token was unset or stale.\n";
        $access_token_data = $this->fetchAccessToken();

        if(!empty($access_token_data->access_token)) {
          $this->access_token_data = $access_token_data;
          $this->access_token = $access_token_data->access_token;
        }
      }
    }

    if (!empty($this->access_token_data)) {
      $expirey = $this->access_token_data->expiration;
      if($this->debug) {
        echo "Token expiration: " . date("Y-m-d h:i:s", $expirey) . "\n";
        echo "Expires in " . ($expirey - $now) . " seconds..\n";
        echo "\n\n";  
      }
      return $this->access_token;    
    }
    else {
      die("\ngetAccessToken() - failed to retrieve access token! X_X\n\n");
    }
  }

  /**
   * Fetch a new access token via the API and return it
   */
  protected function fetchAccessToken() {
    // get an access token
    $bearer_auth_plain = $this->consumer_key . ":" . $this->consumer_secret;
    if ($this->debug) echo "fetchAccessToken() - Tokens: " . $bearer_auth_plain . "\n";
    $bearer_auth = base64_encode($bearer_auth_plain);
    if ($this->debug) echo "fetchAccessToken() - Bearer auth: $bearer_auth\n";

    $access_token_url = $this->base_url . "token?grant_type=client_credentials";
    if ($this->debug) echo "fetchAccessToken() - Access token URL: $access_token_url\n";
    $access_token_headers = [
      "Accept: application/json",
      "Authorization: Basic $bearer_auth",
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $access_token_url);

    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_POST, true);
    // curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $access_token_headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

    if(isset($this->resolve_host)) {
      if ($this->debug) echo "fetchAccessToken() - Resolve host set: " . print_r($this->resolve_host, true) . "\n";
      curl_setopt($ch, CURLOPT_RESOLVE, $this->resolve_host);
      curl_setopt($ch, CURLOPT_PORT, constant($this->soip_constant_name));  
    }

    if($this->debug > 1) {
      curl_setopt($ch, CURLOPT_VERBOSE, true);
    }

    $access_token_start = microtime(true);
    $access_token_result = curl_exec($ch);
    $access_token_error = curl_error($ch);
    curl_close($ch);
    $access_token_finish = microtime(true);
    $access_token_seconds = $access_token_finish - $access_token_start;
    if ($this->debug) echo "fetchAccessToken() - CURL error: " . print_r($access_token_error, true) . "\n";

    if(!empty($access_token_error) || empty($access_token_result)) {
      if ($this->debug) echo "\n$access_token_error\n";
      die("fetchAccessToken() - Failed to fetch access token from the API!!  X_X\n\n");
    }
    else {
      $now = time();
      $access_token_data = json_decode($access_token_result);
      $access_token_data->expiration = (time() + $access_token_data->expires_in);
      $access_token_data->fetched = $now;
  
      if ($this->debug) {
        echo "fetchAccessToken() - Access token result: \n";
        print_r($access_token_result);
        echo "\n";
        echo "fetchAccessToken() - Access token in $access_token_seconds seconds\n";  
        echo "fetchAccessToken() - Now: " . $now . " - " . date("Y-m-d h:i:s", $now) . "\n";
        print_r($access_token_data);
      }
  
      // Save access token data to config
      $env_access_token_setting = 'asc_courses.' . $this->environment . '_access_token';
      if($this->debug) echo "fetchAccessToken() - env_access_token_setting: $env_access_token_setting\n";
      $config = \Drupal::service('config.factory')->getEditable('asc_courses.settings');
      $config->set("asc_courses." . $this->environment . "_access_token", serialize($access_token_data));
      $config->save();
  
      return $access_token_data;
    }
  }

  /**
   * Fetch and store courses for a single D-Org
   */
  public function fetchDorgCourses($dorg, $force = false) {

    if(!$force) {
      if($this->debug) echo "=========================\n";
      $dorg_data = $this->db->select('asc_courses_api_data', 'acad')
        // ->fields('acad', ['asc_courses_api_data_id', 'date', 'dept_org', 'environment', 'request_type', 'processed'])
        ->fields('acad')
        ->condition('dept_org', $dorg, '=')
        ->orderBy('date', 'desc')
        ->range(0,1)
        ->execute()
        ->fetchAssoc();
      // echo "$dorg row: " . print_r($dorg_data, true) . "\n";
      // $data_no_raw = $dorg_data;
      // unset($data_no_raw['raw_json']);
      return $dorg_data;
    }

    $access_token = $this->getAccessToken();
    $course_data_url = $this->base_url . "crseinfo/1.0.0/getCatalogInfo?campus=COL&acad_org=$dorg";

    if($this->debug) echo "course data url: $course_data_url\n";
    $course_data_headers = [
      "Accept: application/json",
      "Authorization: Bearer $access_token"
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $course_data_url);

    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    // curl_setopt($ch, CURLOPT_POST, true);
    // curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $course_data_headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

    if(isset($this->resolve_host)) {
      if ($this->debug) echo "fetchDorgCourses() - Resolve host set: " . $this->resolve_host . "\n";
      // error_log("fetchDorgCourses() - Resolve host set: " . $this->resolve_host);
      curl_setopt($ch, CURLOPT_RESOLVE, $this->resolve_host);
      curl_setopt($ch, CURLOPT_PORT, constant($this->soip_constant_name));  
    }

    if($this->debug > 1) {
      curl_setopt($ch, CURLOPT_VERBOSE, true);
    }

    $curl_start = microtime(true);
    $course_data_result = curl_exec($ch);
    $curl_error = curl_error($ch);
    curl_close($ch);
    $curl_finish = microtime(true);
    $curl_seconds = $curl_finish - $curl_start;
    if ($this->debug) echo "fetchDorgCourses() - CURL error: " . print_r($curl_error, true) . "\n";

    if(!empty($curl_error) || empty($course_data_result)) {
      echo "\n$curl_error\n";
      echo "fetchDorgCourses() - Failed to fetch [$dorg] course information from the API!!  X_X\n\n";
      return 0;
    }
    else {
      if ($this->debug) echo "Course data length:" . strlen($course_data_result) . "\n";
      if ($this->debug) echo "Course data in $curl_seconds seconds\n\n";
  
  
      // $connection = \Drupal::database();
      $row = [
        'date' => time(),
        'environment' => $this->environment,
        'request_type' => 'crseinfo',
        'dept_org' => $dorg,
        'raw_json' => $course_data_result,
        'processed' => 0,
      ];
      $this->db->insert('asc_courses_api_data')->fields($row)->execute();
  
      $course_data = json_decode($course_data_result);      
      return $course_data;
    }


  }

  /**
   * Process one unprocessed `asc_courses_api_data` record for current environment and specified dept_orgs
   */
  public function processDorgCourses($dorg) {
    if ($this->debug) echo "processDorgCourses()\n";
    // $db = \Drupal::database();
    $dorg_query = $this->db->select("asc_courses_api_data", "acad")
        ->fields("acad")
        ->condition("acad.dept_org", $dorg, "=")
        ->condition("processed", "0", "=")
        ->condition("environment", $this->environment, "=");
    $dorg_result = $dorg_query->execute();
    if($row = $dorg_result->fetchAssoc()) {
      $this->processApiDorgCoursesRecord($row);
    }
    else {
      // No unprocessed records found for this environment/dept_org
      if ($this->debug) echo "processDorgCourses(): No unprocessed API data for environment[" . $this->environment . "] and dept_org[" . $dorg . "]\n";
      return false;
    }
  }

  /**
   * Process any remaining unprocessed api data records
   */
  public function processPendingApiData($environment = null, $count = null) {
    if ($this->debug) echo "processAllApiData()\n";
    // $db = \Drupal::database();
    $query = $this->db->select("asc_courses_api_data", "acad")
        ->fields("acad")
        ->condition("processed", "0", "=")
        ->orderBy('date', 'ASC');
    
    if(!empty($environment)) {
      $query->condition("environment", $environment, "=");
    }

    if(!empty($count) && is_numeric($count)) {
      if ($this->debug) echo "processPendingApiData(): Count argument specified: $count";
      $query->range(0, $count);
    }
        
    $api_data_result = $query->execute();
    while($row = $api_data_result->fetchAssoc()) {
      if($row['request_type'] == 'crseinfo') {
        $this->processApiDorgCoursesRecord($row);
      }
      else {
        die("processPendingApiData(): unexpected asc_course_api_data row request_type: " . $row['request_type']);
      }
    }
  }

  /**
   * Process the passed `asc_courses_api_data` row
   */
  public function processApiDorgCoursesRecord($row) {
    if ($this->debug) {
      echo "processApiDorgCoursesRecord()\n";
      echo "asc_courses_api_data_id: " . $row["asc_courses_api_data_id"] . "\n";
      echo "dept_org: " . $row["dept_org"] . "\n";
      echo "date: " . $row["date"] . "\n";
      echo "environment: " . $row["environment"] . "\n";
      echo "request_type: " . $row["request_type"] . "\n";
      echo "processed: " . $row["processed"] . "\n"; 
      echo "json data length: " . strlen($row['raw_json']) . "\n";
    }

    $json_data = json_decode($row['raw_json']);
    if(!$json_data) {
      die("\NprocessDorgCourses(): Something went wrong processing the raw_json\n\n");
    }

    foreach($json_data->getCourseCatalogResponse->catalog->course as $course_data) {
      if(empty($course_data->{'crse-id'})) {
        if ($this->debug) echo "This course has no ID >:( " . print_r($course_data, true) . "\n";
      }
      else {
        $course_data->asc_courses_api_data_id = $row["asc_courses_api_data_id"];
        $course_data->dept_org = $row["dept_org"];
        // print_r($course_data);
        $existing_row = $this->db->select("asc_courses_processed", "acp")
            ->fields("acp")
            ->condition("crse_id", $course_data->{'crse-id'})
            ->execute()
            ->fetchAssoc();
  
        if(!empty($existing_row)) {
          $this->updateProcessedCourse($existing_row, $course_data);
        }
        else {
          $this->insertProcessedCourse($course_data);
        }
      }
    }

    if ($this->debug) echo "=====================\n\n";

    $set_processed_flag = $this->db->update("asc_courses_api_data")
      ->fields(["processed" => 1])
      ->condition("asc_courses_api_data_id", $row["asc_courses_api_data_id"], "=")
      ->execute();
    if ($this->debug) echo "Update processed flag: $set_processed_flag\n";
  }

  /**
   * insert a new course data record into `asc_courses_processed` table
   */
  public function insertProcessedCourse($course_data) {
    if ($this->debug) {
      echo "insertProcessedCourse()";
      echo " - " . $course_data->{'crse-id'};
      echo " - " . $course_data->{'subject'};
      echo " - " . $course_data->{'catalog-nbr'};
      echo " - " . $course_data->{'descr'};
      echo "\n";
      // echo "course data: " . print_r($course_data, true) . "\n";
      // echo "course_title_long length: " . strlen($course_data->{'course-title-long'}) . "\n";  
    }
    $row = [
      "updated" => time(),
      "asc_courses_api_data_id"   => $course_data->{'asc_courses_api_data_id'},      
      "dept_org"                  => $course_data->{'dept_org'},
      "crse_id"                   => $course_data->{'crse-id'},
      "strm"                      => $course_data->{'strm'},
      "effdt"                     => $course_data->{'effdt'},
      "eff_status"                => $course_data->{'eff-status'},
      "descr"                     => $course_data->{'descr'},
      "descrlong"                 => $course_data->{'descrlong'},
      "crse_attribute"            => serialize($course_data->{'crse-attribute'}),
      "equiv_crse_id"             => $course_data->{'equiv-crse-id'},
      "allow_mult_enroll"         => $course_data->{'allow-mult-enroll'},
      "units_minimum"             => $course_data->{'units-minimum'},
      "units_maximum"             => $course_data->{'units-maximum'},
      "acad_prog"                 => $course_data->{'acad-prog'},
      "crse_repeatable"           => $course_data->{'crse-repeatable'},
      "units_repeat_limit"        => $course_data->{'units-repeat-limit'},
      "crse_repeat_limit"         => $course_data->{'crse-repeat-limit'},
      "grading_basis"             => $course_data->{'grading-basis'},
      "ssr_component"             => $course_data->{'ssr-component'},
      "course_title_long"         => $course_data->{'course-title-long'},
      "crse_count"                => $course_data->{'crse-count'},
      "component_primary"         => $course_data->{'component-primary'},
      "crse_offer_nbr"            => $course_data->{'crse-offer-nbr'},
      "acad_group"                => $course_data->{'acad-group'},
      "subject"                   => $course_data->{'subject'},
      "catalog_nbr"               => $course_data->{'catalog-nbr'},
      "campus"                    => $course_data->{'campus'},
      "acad_org"                  => $course_data->{'acad-org'},
      "acad_career"               => $course_data->{'acad-career'},
      "cip_code"                  => $course_data->{'cip-code'},
    ];
    // echo "course row: " . print_r($row, true) . "\n";

    $result = $this->db->insert('asc_courses_processed')->fields($row)->execute();
    if ($this->debug) echo "INSERT result: " . print_r($result, true) . "\n";
    if ($this->debug) echo "\n";
  }

  /**
   * update existing record 
   */
  public function updateProcessedCourse($existing_row, $new_course_data) {
    if ($this->debug) {
      echo "updateProcessedCourse()";
      echo " - " . $new_course_data->{'crse-id'};
      echo " - " . $new_course_data->{'subject'};
      echo " - " . $new_course_data->{'catalog-nbr'};
      echo " - " . $new_course_data->{'descr'};
      echo "\n";
  
      // echo "existing_row: " . print_r($existing_row, true) . "\n";
      // echo "course data: " . print_r($new_course_data, true) . "\n";  
    }

    $row_fields = array_keys($existing_row);

    // echo "row fields: " . print_r($row_fields, true) . "\n";
    
    $new_course_data->{"crse-attribute"} = serialize($new_course_data->{"crse-attribute"});

    $update_fields = [];
    foreach($row_fields as $field_name) {
      $obj_field_name = str_replace("_", "-", $field_name);
      if($existing_row[$field_name] != $new_course_data->{$obj_field_name}) {
        if(
             $field_name != 'asc_courses_processed_id'
          && $field_name != 'updated'
          && $field_name != 'asc_courses_api_data_id'
          && $field_name != 'dept_org'
          && $field_name != 'strm'
        ) {
          if ($this->debug) {
            echo $existing_row[$field_name];
            echo " != ";
            echo $new_course_data->{$obj_field_name} . "\n";  
          }
          $update_fields[$field_name] = $new_course_data->{$obj_field_name};
        }
      }
    }

    unset($update_fields["asc_courses_processed_id"]);  // doesn't come from API
    unset($update_fields["updated"]);  // doesn't come from API
    unset($update_fields["asc_courses_api_data_id"]);  // doesn't come from API
    unset($update_fields["dept_org"]);  // doesn't come from API
    unset($update_fields["strm"]);  // we do not care about duplicates with different 'strm' values
    
    if(empty($update_fields) && $this->debug) {
      echo "updateProcessedCourse(): There is no information to update\n";
    }
    else {
      // echo "existing_row: " . print_r($existing_row, true) . "\n";
      // echo "course data: " . print_r($new_course_data, true) . "\n";
      $update_fields["updated"] = time();
      $update_fields["asc_courses_api_data_id"] = $new_course_data->{'asc_courses_api_data_id'};
      if ($this->debug) echo "Update fields: " . print_r($update_fields, true) . "\n";

      $update_query_result = $this->db->update("asc_courses_processed")
          ->fields($update_fields)
          ->condition("asc_courses_processed_id", $existing_row["asc_courses_processed_id"], "=")
          ->execute();
      if($update_query_result != 1) {
        echo "updateProcessedCourse(): Unexpected number of rows updated: $update_query_result\n";
      }
    }
    if ($this->debug) echo "\n";
    return $update_query_resuilt;
  }



  /**
   * Fetch and store a list of D-Orgs
   */
  public function fetchDorgList() {
    $access_token = $this->getAccessToken();
    $dorg_data_url = $this->base_url . "dept/1.0/detail";

    if($this->debug) echo "D-org data url: $dorg_data_url\n";
    $dorg_data_headers = [
      "Accept: application/json",
      "Authorization: Bearer $access_token",
      "Content-Type: application/json"
    ];

    $dorg_post_data = "{";
    $dorg_post_data .= '"VP_CATEGORY": "ACADEMIC", ';
    $dorg_post_data .= '"VP_AREA": "ARTS_AND_SCIENCES", ';
    $dorg_post_data .= '"VP_COLLEGE": "", ';
    $dorg_post_data .= '"COLLEGE1": "", ';
    $dorg_post_data .= '"COLLEGE2": "", ';
    $dorg_post_data .= '"DEPARTMENT": "", ';
    $dorg_post_data .= '"ORGANIZATION": "", ';
    $dorg_post_data .= '"INCLUDE_HISTORY": "", ';
    $dorg_post_data .= '"EFFDT_YYYYMMDD": ""';
    $dorg_post_data .= "}";
    if($this->debug) echo "D-org POST data: $dorg_post_data\n";

    // $dorg_post_data = [
    //   "VP_CATEGORY" => "ACADEMIC",
    //   "VP_AREA" => "",
    //   "VP_COLLEGE" => "",
    //   "COLLEGE1" => "",
    //   "COLLEGE2" => "",
    //   "DEPARTMENT" => "",
    //   "ORGANIZATION" => "",
    //   "INCLUDE_HISTORY" => "",
    //   "EFFDT_YYYYMMDD" => ""
    // ];
    // if($this->debug) echo "D-org POST data: " . print_r($dorg_post_data, true) . "\n";
    

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $dorg_data_url);

    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $dorg_post_data);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $dorg_data_headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

    if(isset($this->resolve_host)) {
      if ($this->debug) echo "fetchDorgList() - Resolve host set: " . $this->resolve_host . "\n";
      // error_log("fetchDorgList() - Resolve host set: " . $this->resolve_host);
      curl_setopt($ch, CURLOPT_RESOLVE, $this->resolve_host);
      curl_setopt($ch, CURLOPT_PORT, constant($this->soip_constant_name));  
    }

    if($this->debug > 1) {
      curl_setopt($ch, CURLOPT_VERBOSE, true);
    }

    $curl_start = microtime(true);
    $dorg_data_result = curl_exec($ch);
    $curl_error = curl_error($ch);
    curl_close($ch);
    $curl_finish = microtime(true);
    $curl_seconds = $curl_finish - $curl_start;
    if ($this->debug) echo "fetchDorgList() - CURL error: " . print_r($curl_error, true) . "\n";

    if(!empty($curl_error) || empty($dorg_data_result)) {
      echo "\n$curl_error\n";
      die("fetchDorgList() - Failed to fetch D-org list from the API!!  X_X\n\n");
    }
    else {
      if ($this->debug) echo "D-org data length:" . strlen($dorg_data_result) . "\n";
      if ($this->debug) echo "D-org data in $curl_seconds seconds\n\n";
  
  
      // $connection = \Drupal::database();
      $row = [
        'date' => time(),
        // 'dept_org' => $dorg,
        'raw_json' => $dorg_data_result
      ];
      $this->db->insert('asc_course_dorgs')->fields($row)->execute();
  
      $dorg_data = json_decode($dorg_data_result);      
      return $dorg_data;
    }
  }

  public function getApiDorgList() {
    // $connection = \Drupal::database();
    $dorg_info_query = $this->db->select('asc_course_dorgs', 'acd')
      // ->fields('acd', array('id', 'date', 'dept_org'))
      ->fields('acd')
      ->orderBy('date', 'DESC')
      ->range(0, 1);
    $dorg_info_result = $dorg_info_query->execute();
    // $rows = $dorg_info_result->fetchAllAssoc('id', \PDO::FETCH_ASSOC);
    if($row = $dorg_info_result->fetchAssoc()) {
      // print_r($row);
      $data_date = $row['date'];
      $data_age = time() - $data_date;
      if($this->debug) echo "Data date: $data_date - " . date("Y-m-d h:i:s", $data_date) . " - $data_age seconds old\n";

      if($data_age < 36000) {
        if($this->debug) echo "Data is $data_age seconds old.. reusing data from database.\n";
        $dorg_json = $row['raw_json'];
        // $len = strlen($dorg_json);
        if($this->debug) echo "JSON Length:" . strlen($dorg_json) . "\n";
        // echo substr($dorg_json, 0, 1024) . "\n\n";
        $json_data = json_decode($dorg_json);
        // print_r($json_data);
        return $json_data;
      }
      else {
        if($this->debug) echo "D-org data is stale.\n";
        return $this->fetchDorgList();
      }
    }
    else {
      if($this->debug) echo "No D-org data in the database.\n";
      return $this->fetchDorgList();
    }
  }

  public function getDorgList() {
    $dorgs = [
      'D0200' => [
        'name' => "Arts Administration",
      ],
      'D0205' => [
        'name' => "Diversity & Identity Studies C",
      ],
      'D0206' => [
        'name' => "Film Studies",
      ],
      'D0208' => [
        'name' => "Arts Initiatives",
      ],
      'D0210' => [
        'name' => "Adv Computing Ctr/Art & Des",
      ],
      'D0215' => [
        'name' => "Art",
      ],
      'D0225' => [
        'name' => "Arts Education",
      ],
      'D0230' => [
        'name' => "Ind, Intr & Visual Comm Design",
      ],
      'D0235' => [
        'name' => "History of Art",
      ],
      'D0241' => [
        'name' => "Dance",
      ],
      'D0262' => [
        'name' => "School of Music",
      ],
      'D0280' => [
        'name' => "Theatre",
      ],
      'D0500' => [
        'name' => "Humanities Administration",
      ],
      'D0502' => [
        'name' => "AfricanAmer&African Studies",
      ],
      'D0505' => [
        'name' => "Ctr Medieval & Ren Studies",
      ],
      'D0506' => [
        'name' => "Women's Studies",
      ],
      // 'D0507' => [
      //   'name' => "Humanities Information Svcs",
      // ],
      'D0508' => [
        'name' => "Melton Ctr for Jew Studies",
      ],
      'D0509' => [
        'name' => "Greek and Latin",
      ],
      'D0518' => [
        'name' => "Dept of Comp Stds in Hum",
      ],
      'D0527' => [
        'name' => "East Asian Languages & Lit",
      ],
      'D0536' => [
        'name' => "Ctr-Study&Teaching of Writing",
      ],
      'D0537' => [
        'name' => "English",
      ],
      'D0543' => [
        'name' => "Foreign Language Center",
      ],
      'D0545' => [
        'name' => "French and Italian",
      ],
      'D0544' => [
        'name' => "Cntr for the Study of Religion",
      ],
      'D0547' => [
        'name' => "Germanic Languages & Lit",
      ],
      'D0554' => [
        'name' => "Near Eastern Lang & Culture",
      ],
      'D0557' => [
        'name' => "History",
      ],
      'D0564' => [
        'name' => "Humanities Institute",
      ],
      'D0566' => [
        'name' => "Linguistics",
      ],
      'D0575' => [
        'name' => "Philosophy",
      ],
      'D0593' => [
        'name' => "Slavic & East European L&L",
      ],
      'D0596' => [
        'name' => "Spanish and Portugese",
      ],
      // 'D0300' => [
      //   'name' => "Biological Sciences Admin",
      // ],
      'D0303' => [
        'name' => "Ancillary Fac & Services",
      ],
      // 'D0321' => [
      //   'name' => "Div of Sensory Biophysics",
      // ],
      'D0326' => [
        'name' => "Introductory Biology",
      ],
      'D0340' => [
        'name' => "Molecular Genetics",
      ],
      'D0350' => [
        'name' => "Microbiology",
      ],
      'D0385' => [
        'name' => "Plant Biotechnology",
      ],
      'D0386' => [
        'name' => "PMGF",
      ],
      'D0390' => [
        'name' => "EEOB",
      ],
      'D0397' => [
        'name' => "Ohio Biological Survey",
      ],
      // 'D0600' => [
      //   'name' => "Math & Physical Sci Admin",
      // ],
      'D0614' => [
        'name' => "Astronomy",
      ],
      'D0628' => [
        'name' => "Chemistry",
      ],
      'D0656' => [
        'name' => "Geological Sciences",
      ],
      'D0671' => [
        'name' => "Mathematics",
      ],
      'D0684' => [
        'name' => "Physics",
      ],
      'D0694' => [
        'name' => "Statistics",
      ],
      // 'D0700' => [
      //   'name' => "Social & Behav Sci Admin",
      // ],
      // 'D0701' => [
      //   'name' => "Survey Research",
      // ],
      'D0703' => [
        'name' => "Ctr/Human Resource Rsch",
      ],
      'D0707' => [
        'name' => "Mershon Center for Education",
      ],
      'D0708' => [
        'name' => "Population Research Center",
      ],
      'D0709' => [
        'name' => "UG Intl Studies Program",
      ],
      'D0711' => [
        'name' => "Anthropology",
      ],
      'D0722' => [
        'name' => "Economics",
      ],
      'D0733' => [
        'name' => "Geography",
      ],
      'D0735' => [
        'name' => "Urban & Regional Analysis Init",
      ],
      'D0744' => [
        'name' => "Journalism & Communication",
      ],
      'D0755' => [
        'name' => "Political Science",
      ],
      'D0766' => [
        'name' => "Psychology",
      ],
      'D0777' => [
        'name' => "Sociology",
      ],
      'D0778' => [
        'name' => "Criminal Justice Research Ctr",
      ],
      'D0780' => [
        'name' => "Cntr Cognitive & Brain Science",
      ],
      'D0781' => [
        'name' => "Cntr Cog & Behavioral Brain Im",
      ],
      // 'D0782' => [
      //   'name' => "Inst for American Democracy",
      // ],
      'D0783' => [
        'name' => "Neuroscience Ungrad Major",
      ],
      'D0784' => [
        'name' => "Behavioral Decision Making",
      ],
      'D0799' => [
        'name' => "Speech and Hearing",
      ],
    ];
    
    return $dorgs;
  }
}