<?php

/**
 * Add handling of repeated parent pages, they will have the same parent id and id. Do not show children for them and do
 * not add the css class 'pages_with_children'
 *
 * @see Walker and Walker_Page
 */
class Walker_SSD_Page extends Walker_Page
{

    /**
     * This method is a copy of the Walker::display_element member, it add checks for id !== parent_id
     * Traverse elements to create list from elements.
     * Do not traverse children
     *
     * Display one element if the element doesn't have any children otherwise,
     * display the element and its children. Will only traverse up to the max
     * depth and no ignore elements under that depth. It is possible to set the
     * max depth to include all depths, see walk() method.
     *
     * This method should not be called directly, use the walk() method instead.
     *
     * @since 2.5.0
     *
     * @param object $element Data object.
     * @param array $children_elements List of elements to continue traversing.
     * @param int $max_depth Max depth to traverse.
     * @param int $depth Depth of current element.
     * @param array $args An array of arguments.
     * @param string $output Passed by reference. Used to append additional content.
     */
    public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
        if( ! $element ) {
            return;
        }

        $id_field = $this->db_fields[ 'id' ];
        $id = $element->$id_field;
        $parent_field = $this->db_fields[ 'parent' ];
        $parent_id = $element->$parent_field;

        //display this element
        $this->has_children = ( $id !== $parent_id ) && ! empty( $children_elements[ $id ] );
        if( isset( $args[ 0 ] ) && is_array( $args[ 0 ] ) ) {
            $args[ 0 ][ 'has_children' ] = $this->has_children; // Backwards compatibility.
        }

        $cb_args = array_merge( array( &$output, $element, $depth ), $args );
        call_user_func_array( array( $this, 'start_el' ), $cb_args );

        // descend only when the depth is right and there are children for this element
        // and when the id and parent id are not equal
        if( ( $max_depth == 0 || $max_depth > $depth + 1 ) && isset( $children_elements[ $id ] ) && ( $id !== $parent_id ) ) {

            foreach( $children_elements[ $id ] as $child ) {

                if( ! isset( $newlevel ) ) {
                    $newlevel = true;
                    //start the child delimiter
                    $cb_args = array_merge( array( &$output, $depth ), $args );
                    call_user_func_array( array( $this, 'start_lvl' ), $cb_args );
                }
                $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
            }
            unset( $children_elements[ $id ] );
        }

        if( isset( $newlevel ) && $newlevel ) {
            //end the child delimiter
            $cb_args = array_merge( array( &$output, $depth ), $args );
            call_user_func_array( array( $this, 'end_lvl' ), $cb_args );
        }

        //end this element
        $cb_args = array_merge( array( &$output, $element, $depth ), $args );
        if( $id === $parent_id ) {
            unset( $cb_args[ 'pages_with_children' ][ $id ] );
        }
        call_user_func_array( array( $this, 'end_el' ), $cb_args );
    }

    /**
     * Hide children of pages that are shown as child of itself
     *
     * @param string $output
     * @param object $page
     * @param int $depth
     * @param array $args
     * @param int $current_page
     */
    public function start_el( &$output, $page, $depth = 0, $args = array(), $current_page = 0 ) {
        if( $page->ID === $page->post_parent ) {
            unset( $args[ 'pages_with_children' ][ $page->ID ] );
        }
        parent::start_el( $output, $page, $depth, $args, $current_page );
    }
}