<?php

// ------------------------------------------------------------------------- //
//  XooNIps - Neuroinformatics Base Platform System                          //
//  Copyright (C) 2005-2011 RIKEN, Japan All rights reserved.                //
//  http://xoonips.sourceforge.jp/                                           //
// ------------------------------------------------------------------------- //
//  This program is free software; you can redistribute it and/or modify     //
//  it under the terms of the GNU General Public License as published by     //
//  the Free Software Foundation; either version 2 of the License, or        //
//  (at your option) any later version.                                      //
//                                                                           //
//  You may not change or alter any portion of this comment or credits       //
//  of supporting developers from this source code or any supporting         //
//  source code which is considered copyrighted (c) material of the          //
//  original comment or credit authors.                                      //
//                                                                           //
//  This program is distributed in the hope that it will be useful,          //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of           //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
//  GNU General Public License for more details.                             //
//                                                                           //
//  You should have received a copy of the GNU General Public License        //
//  along with this program; if not, write to the Free Software              //
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA //
// ------------------------------------------------------------------------- //
require_once 'lib.php';

/**
 * Return xml with Basic information.
 *
 * To write xml of item to specified folder.
 *
 * In the case of writing attachment file,  at first create a files/ folder
 * in the specified folder.
 * next it write attachment file to the folder.
 *
 * path of xml file is "${export_path}/${item_id}.xml"
 * path of attchment file is "${export_path}/files/${file_id}"
 *
 * If unknown item_id or error in database exists, return false.
 *
 * @param export_path folder that export file is written to
 * @param export_xml name of export file(xml file)
 * @param item_id item id that is exported
 * @param attachment true if attachment files are exported, else false
 *
 * @return returns array(
 *                 'path' => folder that export files are written to.
 *                 'xml' => file path of xml(relative path of 'path')
 *                 'attachments' => arary( file path of attachment 1, file path of
 *                 attachment2, .... ) ) (relative path of 'path')
 *                 return false if failed.
 */
function xnpExportItem($export_path, $item_id, $attachment = false, $is_absolute, $base_index_id = false)
{
    $filename = "${export_path}/${item_id}.xml";
    $tmpfile = tempnam('/tmp', 'XooNIps');

    $fhdl = fopen($tmpfile, 'w');
    if (!$fhdl) {
        xoonips_error_log("can't open file '${tmpfile}' for write.");

        return false;
    }

    $xnpsid = $_SESSION['XNPSID'];
    $item = array();
    $itemtypes = array();

    $res = xnp_get_item($xnpsid, $item_id, $item);
    if (RES_OK != $res) {
        return false;
    }

    $res = xnp_get_item_types($itemtypes);
    if (RES_OK != $res) {
        return false;
    } else {
        foreach ($itemtypes as $i) {
            if ($i['item_type_id'] == $item['item_type_id']) {
                $itemtype = $i;
                break;
            }
        }
    }
    if (!isset($itemtype)) {
        return false;
    }

    require_once XOOPS_ROOT_PATH.'/modules/'.$itemtype['viewphp'];

    if (!fwrite($fhdl, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<item version=\"1.00\">\n")) {
        return false;
    }

    // item type module doesn't support export
    $func = "${itemtype['name']}ExportItem";
    if (!function_exists($func)) {
        return false;
    }

    if (!xnpExportBasic($fhdl, $item_id, $is_absolute, $base_index_id)) {
        return false;
    }

    $attachment_files = $func($export_path, $fhdl, $item_id, $attachment);
    if (!$attachment_files) {
        return false;
    }

    if (!fwrite($fhdl, "</item>\n")) {
        return false;
    }

    fclose($fhdl);

    // convert encoding for client environment
    $fp_r = fopen($tmpfile, 'r');
    $fp_w = fopen($filename, 'w');
    if (!$fp_r || !$fp_w) {
        if (!$fp_r) {
            xoonips_error_log("can't open file '${tmpfile}' for read.");
        }
        if (!$fp_w) {
            xoonips_error_log("can't open file '${filename}' for write.");
        }
        unlink($tmpfile);
        unlink($filename);
        if ($fp_r) {
            fclose($fp_r);
        }
        if ($fp_w) {
            fclose($fp_w);
        }

        return false;
    }
    $unicode = &xoonips_getutility('unicode');
    while (!feof($fp_r)) {
        fputs($fp_w, $unicode->encode_utf8(fgets($fp_r, 131072), xoonips_get_server_charset()));
    }
    fclose($fp_r);
    fclose($fp_w);
    unlink($tmpfile);

    return array('path' => $export_path, 'xml' => "${item_id}.xml", 'attachments' => $attachment_files['attachments']);
}

/**
 * export index.
 *
 * @param $fhdl     file handle that indexes are exported to
 * @param $index_id id of index to display
 * @param $recurse  true:export recursively index that hangs under index_id
 *
 * @return true:success, false:failure
 */
function xnpExportIndex($fhdl, $index_id, $recurse)
{
    if (!$fhdl) {
        return false;
    }
    (method_exists('MyTextSanitizer', 'sGetInstance') and $myts = &MyTextSanitizer::sGetInstance()) || $myts = &MyTextSanitizer::getInstance();

    $xnpsid = $_SESSION['XNPSID'];
    $index = array();
    $child = array();

    $res = xnp_get_index($xnpsid, $index_id, $index);
    if (RES_OK != $res) {
        return false;
    }

    $res = xnp_get_indexes($xnpsid, $index_id, array(), $child);
    if (RES_OK != $res) {
        return false;
    }

    if (!fwrite($fhdl, "<index parent_id=\"${index['parent_index_id']}\" id=\"${index_id}\">\n".'<title>'.$myts->htmlSpecialChars($index['titles'][DEFAULT_INDEX_TITLE_OFFSET])."</title>\n"."</index>\n")) {
        return false;
    }

    $xml = array();
    if ($recurse) {
        $res = xnp_get_indexes($xnpsid, $index_id, array('orders' => array(array('sort_number', 0))), $child);
        if (RES_OK == $res) {
            foreach ($child as $i) {
                if (!xnpExportIndex($fhdl, $i['item_id'], $recurse)) {
                    return false;
                }
            }
        }
    }

    return true;
}

/**
 * exporting attachment files related to item.
 *
 * @param string   $export_path storing directory name
 * @param resource $fhdl        file handle that items are exported to
 * @param int      $item_id     id of item with attachment files to export
 *
 * @return array( 'path' => $export_path,
 *                'attachments' => array( file path of attachment1, file path of attachment2, ... ) )
 *                (relative path of $export_filepath)
 *                returns false if it failed
 */
function xnpExportFile($export_path, $fhdl, $item_id)
{
    $file = xnpGetFileInfo('t_file.file_id, t_file_type.name, t_file.original_file_name, t_file.file_size, t_file.mime_type, t_file.thumbnail_file, t_file.caption', "item_id = ${item_id} and is_deleted=0", $item_id);

    if (!$fhdl) {
        return false;
    }

    // create files directory under $export_path.
    $dir = $export_path.'/files';
    if (!file_exists($dir)) {
        if (!mkdir($dir)) {
            xoonips_error_log("can't make directory '${dir}'");

            return false;
        }
    }

    // for absolete path of attachment file
    $files = array();
    foreach ($file as $f) {
        $file = array();
        list($file['file_id'], $file['file_type_name'], $file['original_file_name'], $file['file_size'], $file['mime_type'], $file['thumbnail_file'], $file['caption']) = $f;

        // copy atatchment file $file['file_id'] to $dir and renamed to original file name
        // output <file> to file handle $fhdl
        $hdl = fopen(xnpGetUploadFilePath($file['file_id']), 'rb');
        if (file_exists(xnpGetUploadFilePath($file['file_id']))) {
            if (!copy(xnpGetUploadFilePath($file['file_id']), $dir.'/'.$file['file_id'])) {
                xoonips_error_log('can\'t write a file \''.$dir.'/'.$file['file_id']."' of the item(ID=${item_id})");

                return false;
            }
            if (!fwrite($fhdl, '<file'." item_id=\"${item_id}\""." file_type_name=\"${file['file_type_name']}\""." original_file_name=\"${file['original_file_name']}\""." file_name=\"files/${file['file_id']}\""." file_size=\"${file['file_size']}\""." mime_type=\"${file['mime_type']}\"".">\n".(isset($file['thumbnail_file']) ? '<thumbnail>'.base64_encode($file['thumbnail_file'])."</thumbnail>\n" : '').'<caption>'.$file['caption']."</caption>\n"."</file>\n")) {
                fclose($hdl);
                xoonips_error_log("can't export <file> of the item(ID=${item_id})");

                return false;
            }
            $files[] = "files/${file['file_id']}";
        }
    }

    return true;
}

/**
 * export Basic information of item.
 *
 * @param $fhdl          file handle that items are exported to
 * @param $item_id       id of the item to change into XML
 * @param $is_absolute
 * @param $base_index_id
 *
 * @return true:success, false:failure
 */
function xnpExportBasic($fhdl, $item_id, $is_absolute, $base_index_id = false)
{
    if (!$fhdl) {
        return false;
    }

    $xnpsid = $_SESSION['XNPSID'];
    $item = array();
    $account = array();

    $res = xnp_get_item($xnpsid, $item_id, $item);
    if (RES_OK != $res) {
        return false;
    }

    return xnpBasicInformation2XML($fhdl, $item, $is_absolute, $base_index_id);
}

/**
 * export ChangeLog of item.
 *
 * @param $fhdl    file handle that changelogs are exported to
 * @param $item_id item id of the item to export
 *
 * @return true:success, false:failure
 */
function xnpExportChangeLog($fhdl, $item_id)
{
    if (!$fhdl) {
        return false;
    }
    (method_exists('MyTextSanitizer', 'sGetInstance') and $myts = &MyTextSanitizer::sGetInstance()) || $myts = &MyTextSanitizer::getInstance();

    $xnpsid = $_SESSION['XNPSID'];
    $xml = array();
    $logs = array();
    $res = xnp_get_change_logs($xnpsid, $item_id, $logs);
    if (RES_OK != $res) {
        return false;
    }
    if (!fwrite($fhdl, "<changelogs>\n")) {
        return false;
    }
    foreach ($logs as $l) {
        $log_date = gmdate('Y-m-d\\TH:i:s\\Z', $l['log_date']);
        if (!fwrite($fhdl, "<changelog date='${log_date}'>".$myts->htmlSpecialChars($l['log'])."</changelog>\n")) {
            return false;
        }
    }
    if (!fwrite($fhdl, "</changelogs>\n")) {
        return false;
    }

    return true;
}

/**
 * export 'Related to' information of an item.
 *
 * @param $parent_id id of the item to export
 *
 * @return string|null XML or NULL
 */
function xnpExportRelatedTo($parent_id)
{
    $xnpsid = $_SESSION['XNPSID'];
    $xml = array();
    $item_id = array();
    // Export item: only accesible item
    // ->export link information getted xnp_get_related_to.
    $res = xnp_get_related_to($xnpsid, $parent_id, $item_id);
    if (RES_OK != $res) {
        return null;
    }
    $xml = '';
    foreach ($item_id as $i) {
        $xml = $xml."<related_to item_id='${i}'/>\n";
    }

    return $xml;
}

// Import
$parser_hash = array();

/**
 * @param string $str             XML characters (UTF-8)
 * @param int    $parent_index_id index_id of import place
 * @param array  &$id_table       array( 'pseudo ID' => 'actual ID', ... ) effected index ids
 * @param string &$errmsg         reference recieve error message
 *
 * @return bool|null false if falure. refer $errmsg.
 */
function xnpImportIndex($str, $parent_index_id, &$id_table, &$errmsg)
{
    global $parser_hash;
    $textutil = &xoonips_getutility('text');

    $uid = $_SESSION['xoopsUserId'];
    $xnpsid = $_SESSION['XNPSID'];
    $item = array();

    $str = mb_decode_numericentity($str, xoonips_get_conversion_map(), 'UTF-8');
    $parser = xml_parser_create('UTF-8');
    if (!$parser) {
        $errmsg .= "can't create parser\n";

        return false;
    }
    $parser_hash[$parser] = array(
        'tagstack' => array(),
        'id_table' => $id_table,
        'errmsg' => $errmsg,
        'handler' => array(),
        'handlerstack' => array(),
        'indexes' => array(),
        'parent_index_id' => $parent_index_id,
    );

    $parser_hash[$parser]['handler']['/INDEXES'] = array(
        '_xoonips_import_indexStartElement',
        '_xoonips_import_indexEndElement',
        '_xoonips_import_indexCharacterData',
    );

    xml_set_element_handler($parser, '_xoonips_import_startElement', '_xoonips_import_endElement');
    xml_set_character_data_handler($parser, '_xoonips_import_CharacterData');

    if (!xml_parse($parser, $str, true)) {
        $lines = preg_split("/[\r\n]+/", $str);
        die(xml_error_string(xml_get_error_code($parser)).' at column '.xml_get_current_column_number($parser).' of line '.$textutil->html_special_chars($lines[xml_get_current_line_number($parser) - 1]));
    }

    xml_parser_free($parser);

    $id_table = $parser_hash[$parser]['id_table'];
    $parser_hash[$parser] = null;

    return true;
}

function xnpImportIndexCheck($str, &$indexes)
{
    global $parser_hash;
    $textutil = &xoonips_getutility('text');

    $xnpsid = $_SESSION['XNPSID'];
    $item = array();

    $str = mb_decode_numericentity($str, xoonips_get_conversion_map(), 'UTF-8');
    $parser = xml_parser_create('UTF-8');
    if (!$parser) {
        return null;
    }
    $parser_hash[$parser] = array(
        'tagstack' => array(),
        'indexes' => array(),
        'handler' => array(),
        'handlerstack' => array(),
    );
    // XooNIps processes following tags.
    $parser_hash[$parser]['handler']['/INDEXES'] = array(
        '_xoonips_import_indexcheckStartElement',
        '_xoonips_import_indexcheckEndElement',
        '_xoonips_import_indexcheckCharacterData',
    );

    xml_set_element_handler($parser, '_xoonips_import_startElement', '_xoonips_import_endElement');
    xml_set_character_data_handler($parser, '_xoonips_import_CharacterData');

    if (!xml_parse($parser, $str, true)) {
        $lines = preg_split("/[\r\n]+/", $str);
        die(xml_error_string(xml_get_error_code($parser)).' at column '.xml_get_current_column_number($parser).' of line '.$textutil->html_special_chars($lines[xml_get_current_line_number($parser) - 1]));
    }

    xml_parser_free($parser);

    $indexes = $parser_hash[$parser]['indexes'];
    $parser_hash[$parser] = null;

    return true;
}

/**
 * private functions
 * these functions will be called from this file.
 */

// parser handlers for index
function _xoonips_import_startElement($parser, $name, $attribs)
{
    global $currentTag, $currentAttribs;
    global $parser_hash;
    $currentTag = $name;

    // return if item_id is not in accept_id
    if (array_key_exists('basic', $parser_hash[$parser]) && array_key_exists('ID', $parser_hash[$parser]['basic']) && !in_array($parser_hash[$parser]['basic']['ID'], $parser_hash[$parser]['accept_id'])) {
        return;
    }

    $currentAttribs = $attribs;

    array_push($parser_hash[$parser]['tagstack'], $name);

    $tags = '/'.implode('/', $parser_hash[$parser]['tagstack']);
    if (array_key_exists($tags, $parser_hash[$parser]['handler'])) {
        array_push($parser_hash[$parser]['handlerstack'], $parser_hash[$parser]['handler'][$tags]);
    }

    if (count($parser_hash[$parser]['handlerstack']) > 0) {
        $handler = end($parser_hash[$parser]['handlerstack']);
        if (function_exists($handler[0])) {
            $handler[0]($parser, $name, $attribs, $parser_hash[$parser]);
        }

        return;
    }
}

function _xoonips_import_endElement($parser, $name)
{
    global $currentTag;
    global $parser_hash;

    // return if item_id is not in accept_id
    if (array_key_exists('basic', $parser_hash[$parser]) && array_key_exists('ID', $parser_hash[$parser]['basic']) && !in_array($parser_hash[$parser]['basic']['ID'], $parser_hash[$parser]['accept_id'])) {
        return;
    }

    if (count($parser_hash[$parser]['handlerstack']) > 0) {
        $handler = end($parser_hash[$parser]['handlerstack']);
        if (function_exists($handler[1])) {
            $handler[1]($parser, $name, $parser_hash[$parser]);
        }
        // TODO: compare with first value in 'handler' key.
        if (array_key_exists('/'.implode('/', $parser_hash[$parser]['tagstack']), $parser_hash[$parser]['handler'])) {
            array_pop($parser_hash[$parser]['handlerstack']);
        }
        array_pop($parser_hash[$parser]['tagstack']);

        return;
    }

    $currentTag = '';
    $currentAttribs = '';

    array_pop($parser_hash[$parser]['tagstack']);
}

function _xoonips_import_CharacterData($parser, $data)
{
    global $currentTag, $currentAttribs;
    global $parser_hash;

    // return if item_id is not in accept_id
    if (array_key_exists('basic', $parser_hash[$parser]) && array_key_exists('ID', $parser_hash[$parser]['basic']) && !in_array($parser_hash[$parser]['basic']['ID'], $parser_hash[$parser]['accept_id'])) {
        return;
    }

    $tags = '/'.implode('/', $parser_hash[$parser]['tagstack']);

    if (count($parser_hash[$parser]['handlerstack']) > 0) {
        $handler = end($parser_hash[$parser]['handlerstack']);
        if (function_exists($handler[2])) {
            $handler[2]($parser, $data, $parser_hash[$parser]);
        }

        return;
    }
}

// parser handlers for index
function _xoonips_import_indexStartElement($parser, $name, $attribs, &$parser_hash)
{
    $xnpsid = $_SESSION['XNPSID'];

    $tags = '/'.implode('/', $parser_hash['tagstack']);

    switch ($tags) {
    case '/INDEXES/INDEX/TITLE':
        // prepare a new buffer of index title to read
        $parser_hash['indexes'][count($parser_hash['indexes']) - 1]['titles'][] = '';
        break;
    case '/INDEXES/INDEX':
        $ar = array(
            'parent_id' => $attribs['PARENT_ID'],
            'index_id' => $attribs['ID'],
            'titles' => array(),
        );
        array_push($parser_hash['indexes'], $ar);
        break;
    case '/INDEXES':
        break;
    }
}

function _xoonips_import_indexEndElement($parser, $name, &$parser_hash)
{
    $xnpsid = $_SESSION['XNPSID'];

    switch ($name) {
    case 'INDEXES':
        $indexes = $parser_hash['indexes'];

        // To construct tree structure from given indexes by $indexes
        // associative array (parent ID -> array of child ID)
        $p2c = array();
        // $index_by_id[ index_id ] => index array;
        $index_by_id = array();
        foreach ($indexes as $i) {
            if (!isset($p2c[$i['parent_id']])) {
                $p2c[$i['parent_id']] = array();
            }
            $p2c[$i['parent_id']][] = $i['index_id'];
            $index_by_id[$i['index_id']] = $i;
        }

        // Index id of root of each index trees
        $root_ids = array();
        foreach ($index_by_id as $index_id => $index) {
            if (!isset($index_by_id[$index['parent_id']])) {
                $root_ids[] = $index_id;
            }
        }
        // structured index tree
        $tree = array();
        foreach ($root_ids as $root_id) {
            $tree[] = _xoonips_import_constructIndexTree($p2c, $index_by_id, $root_id);
        }

        _xoonips_import_index($parser_hash['parent_index_id'], $tree, $parser_hash['id_table']);
        break;
    }
}

function _xoonips_import_indexCharacterData($parser, $data, &$parser_hash)
{
    $tags = '/'.implode('/', $parser_hash['tagstack']);

    switch ($tags) {
    case '/INDEXES/INDEX/TITLE':
        $index = array_pop($parser_hash['indexes']);
        $index['titles'][count($index['titles']) - 1] .= $data;
        array_push($parser_hash['indexes'], $index);
        break;
    }
}

// parser handlers for index check
function _xoonips_import_indexcheckStartElement($parser, $name, $attribs, &$parser_hash)
{
    $tags = '/'.implode('/', $parser_hash['tagstack']);

    switch ($tags) {
    case '/INDEXES':
        $parser_hash['indexlinks'] = array();
        break;
    case '/INDEXES/INDEX':
        $ar = array(
            'parent_id' => $attribs['PARENT_ID'],
            'index_id' => $attribs['ID'],
            'titles' => array(),
        );
        array_push($parser_hash['indexes'], $ar);
        break;
    case '/INDEXES/INDEX/TITLE':
        $parser_hash['indexes'][count($parser_hash['indexes']) - 1]['titles'][] = '';
        break;
    }
}

function _xoonips_import_indexcheckEndElement($parser, $name, &$parser_hash)
{
    $tags = '/'.implode('/', $parser_hash['tagstack']);

    switch ($tags) {
    case '/INDEXES/INDEX/TITLE':
        $title = &$parser_hash['indexes'][count($parser_hash['indexes']) - 1]['titles'][count($parser_hash['indexes'][count($parser_hash['indexes']) - 1]['titles']) - 1];
        $unicode = &xoonips_getutility('unicode');
        $title = $unicode->decode_utf8($title, xoonips_get_server_charset(), 'h');
        break;
    }
}

function _xoonips_import_indexcheckCharacterData($parser, $data, &$parser_hash)
{
    $tags = '/'.implode('/', $parser_hash['tagstack']);

    switch ($tags) {
    case '/INDEXES/INDEX/TITLE':
        $parser_hash['indexes'][count($parser_hash['indexes']) - 1]['titles'][count($parser_hash['indexes'][count($parser_hash['indexes']) - 1]['titles']) - 1] .= $data;
        break;
    }
}

/**
 * Importing indexes to a index that is specified by $parent_index_id.
 * Associations of pseudo ID and Real index ID are sotred to $id_table.
 *
 * @param int   $parent_index_id index_id that indexes is imported to
 * @param array &$indexes        array of index information to be imported.
 *                               $indexes = array(
 *                               array( 'titles' => array( TITLE1, TITLE2, ... )
 *                               'parent_id' => pseudo id of parent index
 *                               'item_id' => pseudo id of own index
 *                               'child' => array( [0] => array( 'titles' => ..., 'parent_id' => ..., 'child' => ....)
 *                               [1] => array( same above ),
 *                               ....
 *                               )
 *                               ),
 *                               array( 'titles' => array( TITLE1, TITLE2, ... )
 *                               same above ... ),
 *                               ...
 *                               );
 * @param int   &$id_table       reference of associative array for output( [pseudo id] => [real index id] )
 *
 * @return no return value
 */
function _xoonips_import_index($parent_index_id, &$indexes, &$id_table)
{
    $xnpsid = $_SESSION['XNPSID'];
    $lengths = xnpGetColumnLengths('xoonips_item_title');
    $unicode = &xoonips_getutility('unicode');
    foreach ($indexes as $index) {
        foreach ($index['titles'] as $k => $title) {
            list($index['titles'][$k], $dummy) = xnpTrimString($unicode->decode_utf8($title, xoonips_get_server_charset(), 'h'), $lengths['title'], 'UTF-8');
        }
        $child = array();
        // numbers of same index name
        $cnt = 0;
        $index_id = 0;
        if (RES_OK == xnp_get_indexes($xnpsid, $parent_index_id, array(), $child)) {
            foreach ($child as $i) {
                $diff = array_diff($i['titles'], $index['titles']);
                if (empty($diff)) {
                    // true if $index have only same names of $i ( $i['titles'] == $index['titles'] )
                    ++$cnt;
                    $index_id = $i['item_id'];
                }
            }
        }
        if (1 == $cnt) {
            $id_table[$index['index_id']] = $index_id;
        } else {
            $insert_index = array();
            $insert_index['titles'] = $index['titles'];
            $insert_index['parent_index_id'] = $parent_index_id;
            $result = xnp_insert_index($xnpsid, $insert_index, $index_id);
            if (RES_OK != $result) {
                break;
            }
            $id_table[$index['index_id']] = $index_id;

            // record event log
            $mydirname = basename(dirname(__DIR__));
            $event_handler = &xoonips_getormhandler('xoonips', 'event_log');
            $event_handler->recordInsertIndexEvent($index_id);
        }
        if (array_key_exists('child', $index)) {
            _xoonips_import_index($index_id, $index['child'], $id_table);
        }
    }
}

/**
 * To construct tree structure of the index.
 * The root of the tree structue is specified by $root_id.
 * Return value of this function has information of this index and the childs of this index.
 * This function is called recursive by own.
 *
 * @param array $p2c         p2c[ Parent ID of the index ] = array( ID of child index of the index[0], ...[1], ...[2], .... )
 * @param int   $index_by_id assosiative array of index( index information that is associated by own index ID )
 *                           $index_by_id[ ID of the index 'A' ] = array( information of the index 'A' )
 * @param int   $root_id     Index ID of the root of the index tree structure that you want to get
 *
 * @return assosiative array of index tree
 */
function _xoonips_import_constructIndexTree($p2c, $index_by_id, $root_id)
{
    $ret = $index_by_id[$root_id];

    if (isset($p2c[$root_id])) {
        // call _xoonips_import_constructIndexTree if index(id=$root_id) has
        // child indexes
        foreach ($p2c[$root_id] as $child_id) {
            $ret['child'][] = _xoonips_import_constructIndexTree($p2c, $index_by_id, $child_id);
        }
    }

    return $ret;
}
