/**
     * Retrieve all of the material relevant to a given law.
     */
    function get_law()
    {
        /*
         * We're going to need access to the database connection throughout this class.
         */
        global $db;
        /*
         * If neither a section number nor a law ID has been passed to this function, then there's
         * nothing to do.
         */
        if (!isset($this->section_number) && !isset($this->law_id)) {
            return FALSE;
        }
        /*
         * If we haven't specified which fields that we want, then assume that we want all of them.
         */
        if (!isset($this->config) || !is_object($this->config)) {
            $this->config = new StdClass();
            $this->config->get_all = TRUE;
        }
        /*
         * Define the level of detail that we want from this method. By default, we return
         * everything that we have for this law.
         */
        if (!isset($this->config) || $this->config->get_all == TRUE) {
            $this->config->get_text = TRUE;
            $this->config->get_structure = TRUE;
            $this->config->get_amendment_attempts = TRUE;
            $this->config->get_court_decisions = TRUE;
            $this->config->get_metadata = TRUE;
            $this->config->get_references = TRUE;
            $this->config->get_related_laws = TRUE;
            $this->config->get_tags = TRUE;
            $this->config->render_html = TRUE;
        }
        /*
         * Assemble the query that we'll use to get this law.
         */
        $sql = 'SELECT id AS section_id, structure_id, section AS section_number, catch_line,
				history, text AS full_text, order_by
				FROM laws';
        $sql_args = array();
        /*
         * If we're requesting a specific law by ID.
         */
        if (isset($this->law_id)) {
            /*
             * If it's just a single law ID, then just request the one.
             */
            if (!is_array($this->law_id)) {
                $sql .= ' WHERE id = :id';
                $sql_args[':id'] = $this->law_id;
            } elseif (is_array($this->law_id)) {
                $sql .= ' WHERE (';
                /*
                 * Step through the list.
                 */
                $law_count = count($this->law_id);
                for ($i = 0; $i < $law_count; $i++) {
                    $sql .= " id = :id{$i}";
                    $sql_args[":id{$i}"] = $this->law_id[$i];
                    if ($i < $law_count - 1) {
                        $sql .= ' OR';
                    }
                }
                $sql .= ')';
            }
        } else {
            $sql .= ' WHERE section = :section_number
					AND edition_id = :edition_id';
            $sql_args[':section_number'] = $this->section_number;
            if (isset($this->edition_id)) {
                $sql_args[':edition_id'] = $this->edition_id;
            } else {
                $sql_args[':edition_id'] = EDITION_ID;
            }
        }
        $statement = $db->prepare($sql);
        $result = $statement->execute($sql_args);
        if ($result === FALSE || $statement->rowCount() == 0) {
            return FALSE;
        }
        /*
         * Return the result as an object.
         */
        $tmp = $statement->fetch(PDO::FETCH_OBJ);
        /*
         * Bring this law into the object scope.
         */
        foreach ($tmp as $key => $value) {
            $this->{$key} = $value;
        }
        /*
         * Clean up the typography in the full text.
         */
        $this->full_text = wptexturize($this->full_text);
        /*
         * Now get the text for this law, subsection by subsection.
         */
        if ($this->config->get_text === TRUE) {
            /*
             * When invoking this method in a loop, $this->text can pile up on itself. If the text
             * property is already set, clear it out.
             */
            if (isset($this->text)) {
                unset($this->text);
            }
            $sql = 'SELECT id, text, type,
						(SELECT
							GROUP_CONCAT(identifier
							ORDER BY sequence ASC
							SEPARATOR "|")
						FROM text_sections
						WHERE text_id=text.id
						GROUP BY text_id) AS prefixes
					FROM text
					WHERE law_id = :law_id
					ORDER BY text.sequence ASC';
            $sql_args = array(':law_id' => $this->section_id);
            $statement = $db->prepare($sql);
            $result = $statement->execute($sql_args);
            /*
             * If the query fails, or if no results are found, return false -- we can't make a
             * match.
             */
            if ($result === FALSE || $statement->rowCount() == 0) {
                return FALSE;
            }
            /*
             * Iterate through all of the sections of text to save to our object.
             */
            $i = 0;
            while ($tmp = $statement->fetch(PDO::FETCH_OBJ)) {
                $tmp->prefixes = explode('|', $tmp->prefixes);
                $tmp->prefix = end($tmp->prefixes);
                $tmp->entire_prefix = implode('', $tmp->prefixes);
                $tmp->prefix_anchor = str_replace(' ', '_', $tmp->entire_prefix);
                $tmp->level = count($tmp->prefixes);
                /*
                 * Pretty it up, converting all straight quotes into directional quotes, double
                 * dashes into em dashes, etc.
                 */
                if ($tmp->type != 'table') {
                    $tmp->text = wptexturize($tmp->text);
                }
                /*
                 * Append this section.
                 */
                if (!isset($this->text)) {
                    $this->text = new StdClass();
                }
                $this->text->{$i} = $tmp;
                $i++;
            }
        }
        /*
         * Determine this law's structural position.
         */
        if ($this->config->get_structure = TRUE) {
            /*
             * Create a new instance of the Structure class.
             */
            $struct = new Structure();
            /*
             * Our structure ID provides a starting point to identify this law's ancestry.
             */
            $struct->id = $this->structure_id;
            /*
             * Save the law's ancestry.
             */
            $this->ancestry = $struct->id_ancestry();
            /*
             * Short of a parser error, there’s no reason why a law should not have an ancestry. In
             * case of this unlikely possibility, just erase the false element.
             */
            if ($this->ancestry === FALSE) {
                unset($this->ancestry);
            }
            /*
             * Get the listing of all other sections in the structural unit that contains this
             * section.
             */
            $this->structure_contents = $struct->list_laws();
            /*
             * Figure out what the next and prior sections are (we may have 0-1 of either). Iterate
             * through all of the contents of the chapter. (It's possible that there are no next or
             * prior sections, such as in a single-item structural unit.)
             */
            if ($this->structure_contents !== FALSE) {
                $tmp = count((array) $this->structure_contents);
                for ($i = 0; $i < $tmp; $i++) {
                    /*
                     * When we get to our current section, that's when we get to work.
                     */
                    if ($this->structure_contents->{$i}->id == $this->section_id) {
                        $j = $i - 1;
                        $k = $i + 1;
                        if (isset($this->structure_contents->{$j})) {
                            $this->previous_section = $this->structure_contents->{$j};
                        }
                        if (isset($this->structure_contents->{$k})) {
                            $this->next_section = $this->structure_contents->{$k};
                        }
                        break;
                    }
                }
            }
        }
        /*
         * Gather all metadata stored about this law.
         */
        if ($this->config->get_metadata == TRUE) {
            $this->metadata = Law::get_metadata();
        }
        /*
         * Gather any tags applied to this law.
         */
        if ($this->config->get_tags == TRUE) {
            $sql = 'SELECT text
					FROM tags
					WHERE law_id = ' . $db->quote($this->section_id);
            $result = $db->query($sql);
            if ($result !== TRUE && $result->rowCount() > 0) {
                $this->tags = new stdClass();
                $i = 0;
                while ($tag = $result->fetch(PDO::FETCH_OBJ)) {
                    $this->tags->{$i} = $tag->text;
                    $i++;
                }
            }
        }
        /*
         * Create a new instance of the State() class.
         */
        $state = new State();
        $state->section_id = $this->section_id;
        $state->section_number = $this->section_number;
        /*
         * Get the amendment attempts for this law and include those (if there are any). But
         * only if we have specifically requested this data. That's because, on most installations,
         * this will be making a call to a third-party service (e.g., Open States), and such a call
         * is expensive.
         */
        if ($this->config->get_amendment_attempts == TRUE) {
            if (method_exists($state, 'get_amendment_attempts')) {
                if ($state->get_amendment_attempts() !== FALSE) {
                    $this->amendment_attempts = $state->bills;
                }
            }
        }
        /*
         * Get the court decisions that affect this law and include those (if there are any). But
         * only if we have specifically requested this data. That's because, on most installations,
         * this will be making a call to a third-party service and such a call is expensive.
         */
        if ($this->config->get_court_decisions == TRUE) {
            /*
             * If we already have this data cached as metadata.
             */
            if (isset($this->metadata->court_decisions)) {
                $this->court_decisions = $this->metadata->court_decisions;
            } else {
                if (method_exists($state, 'get_court_decisions')) {
                    if ($state->get_court_decisions() !== FALSE) {
                        $this->court_decisions = $state->decisions;
                    }
                }
            }
        }
        /*
         * Get the URL for this law on its official state web page.
         */
        if (method_exists($state, 'official_url')) {
            $this->official_url = $state->official_url();
        }
        /*
         * Translate the history of this law into plain English.
         */
        if (method_exists($state, 'translate_history')) {
            if (isset($this->metadata->history)) {
                $state->history = $this->metadata->history;
                $this->history_text = $state->translate_history();
            }
        }
        /*
         * Generate citations for this law.
         */
        if (method_exists($state, 'citations')) {
            $state->section_number = $this->section_number;
            $state->citations();
            $this->citation = $state->citation;
        }
        /*
         * Get the references to this law among other laws and include those (if there are any).
         */
        if ($this->config->get_references == TRUE) {
            $this->references = Law::get_references();
        }
        /*
         * Gather all laws that are textually similar to this law.
         */
        if ($this->config->get_related_laws == TRUE) {
            //$this->metadata = Law::get_related();
        }
        /*
         * Pretty up the text for the catch line.
         */
        $this->catch_line = wptexturize($this->catch_line);
        /*
         * Provide the URL for this section.
         */
        $sql = 'SELECT url, token
				FROM permalinks
				WHERE relational_id = :id
				AND object_type = :object_type';
        $statement = $db->prepare($sql);
        $sql_args = array(':id' => $this->section_id, ':object_type' => 'law');
        $result = $statement->execute($sql_args);
        if ($result !== FALSE && $statement->rowCount() > 0) {
            $permalink = $statement->fetch(PDO::FETCH_OBJ);
            $this->url = $permalink->url;
            $this->token = $permalink->token;
        }
        /*
         * List the URLs for the textual formats in which this section is available.
         */
        if (!isset($this->formats)) {
            $this->formats = new StdClass();
        }
        $this->formats->txt = substr($this->url, 0, -1) . '.txt';
        $this->formats->json = substr($this->url, 0, -1) . '.json';
        $this->formats->json = substr($this->url, 0, -1) . '.xml';
        /*
         * Create metadata in the Dublin Core format.
         */
        $this->dublin_core = new stdClass();
        $this->dublin_core->Title = $this->catch_line;
        $this->dublin_core->Type = 'Text';
        $this->dublin_core->Format = 'text/html';
        $this->dublin_core->Identifier = SECTION_SYMBOL . ' ' . $this->section_number;
        $this->dublin_core->Relation = LAWS_NAME;
        /*
         * If the request specifies that rendered HTML should be returned, then generate that.
         */
        if (isset($this->config->render_html) && $this->config->render_html === TRUE) {
            $this->html = Law::render();
        }
        /*
         * Provide a plain text version of this law.
         */
        $this->plain_text = Law::render_plain_text();
        /*
         * Provide a plain text document header.
         */
        $this->plain_text = str_repeat(' ', round((81 - strlen(LAWS_NAME)) / 2)) . strtoupper(LAWS_NAME) . "\n\n" . wordwrap(strtoupper($this->catch_line) . ' (' . SECTION_SYMBOL . ' ' . $this->section_number . ')', 80, "\n", TRUE) . "\n\n" . $this->plain_text;
        if (!empty($this->history)) {
            $this->plain_text .= "\n" . wordwrap('HISTORY: ' . $this->history, 80, "\n", TRUE);
        }
        $law = $this;
        unset($law->config);
        return $law;
    }
    /**
     * Get a list of defined terms for a given structural unit of the code, returning just a listing
     * of terms. (The idea is that we can use an Ajax call to get each definition on demand.)
     */
    function term_list()
    {
        /*
         * We're going to need access to the database connection throughout this class.
         */
        global $db;
        /*
         * If a structural ID hasn't been passed to this function, then return a listing of terms
         * that apply to the entirety of the code.
         */
        if (!isset($this->structure_id) && !isset($this->scope)) {
            $this->scope = 'global';
        }
        /*
         * If we haven't specified whether we want to include generic terms
         * in this query, include them by default.
         */
        if (!isset($this->generic_terms)) {
            $this->generic_terms = TRUE;
        }
        /*
         * Create an object in which we'll store terms that are identified.
         */
        $terms = new stdClass();
        /*
         * Get a listing of all structural units that contain the current structural unit -- that is,
         * if this is a chapter, get the ID of both the chapter and the title. And so on.
         */
        if (isset($this->structure_id)) {
            $heritage = new Structure();
            $heritage->id = $this->structure_id;
            $ancestry = $heritage->id_ancestry();
            $tmp = array();
            foreach ($ancestry as $level) {
                $tmp[] = $level->id;
            }
            $ancestry = $tmp;
            unset($tmp);
        }
        /*
         * Get a list of all globally scoped terms.
         */
        $sql_args = array(':global_scope' => 'global');
        if (isset($this->scope) && $this->scope == 'global') {
            $sql = 'SELECT dictionary.term
					FROM dictionary
					LEFT JOIN laws
						ON dictionary.law_id=laws.id
					 WHERE scope = :global_scope';
        } else {
            $sql = 'SELECT DISTINCT dictionary.term
					FROM dictionary
					LEFT JOIN laws
						ON dictionary.law_id=laws.id
					LEFT JOIN structure
						ON laws.structure_id=structure.id
					WHERE
					(
						(dictionary.law_id=:section_id)
						AND
						(dictionary.scope=:section_scope)
					)';
            $sql_args[':section_id'] = $this->section_id;
            $sql_args[':section_scope'] = 'section';
            $ancestry_count = count($ancestry);
            for ($i = 0; $i < $ancestry_count; $i++) {
                $sql .= " OR (dictionary.structure_id=:structure{$i})";
                $sql_args[":structure{$i}"] = $ancestry[$i];
            }
            $sql .= ' OR (scope=:global_scope)';
        }
        $statement = $db->prepare($sql);
        $result = $statement->execute($sql_args);
        /*
         * Establish the counter we'll use as our object numbering scheme throughout both of our
         * queries.
         */
        $i = 0;
        /*
         * If any terms are found, then add them to our $terms object.
         */
        if ($statement->rowCount() > 1) {
            /*
             * Build up the result as an object as we loop through the results.
             */
            while ($term = $statement->fetch(PDO::FETCH_OBJ)) {
                $terms->{$i} = $term->term;
                $i++;
            }
        }
        /*
         * Assemble a second query, this one against our generic legal dictionary, but only if we
         * have opted to include generic terms.
         */
        if ($this->generic_terms === TRUE) {
            $sql = 'SELECT term
					FROM dictionary_general';
            $sql_args = null;
            $statement = $db->prepare($sql);
            $result = $statement->execute($sql_args);
            if ($result !== FALSE && $statement->rowCount() > 0) {
                /*
                 * Append these results to the existing $terms object, continuing to use the previously-
                 * defined $i counter.
                 */
                while ($term = $statement->fetch(PDO::FETCH_OBJ)) {
                    $terms->{$i} = $term->term;
                    $i++;
                }
            }
        }
        $tmp = (array) $terms;
        $tmp = array_unique($tmp);
        $terms = (object) $tmp;
        return $terms;
    }