/** guifi_node_ariadna(): Get an array of zone hierarchy and node devices
 * to build the breadcrumb
**/
function guifi_node_ariadna($node, $nlink = 'node/%d', $dlink = 'guifi/device/%d', $zlink = 'node/%s')
{
    if (is_numeric($node)) {
        $node = guifi_node_load($node);
        $node->title = $node->nick;
        // hack to show the node title
    }
    $ret = array();
    $ret[] = l(t('Home'), NULL);
    $ret[] = l(t('Main menu'), 'guifi');
    foreach (array_reverse(guifi_zone_get_parents($node->zone_id)) as $parent) {
        if ($parent > 0) {
            $parentData = db_fetch_array(db_query('SELECT z.id, z.title ' . 'FROM {guifi_zone} z ' . 'WHERE z.id = %d ', $parent));
            $ret[] = l($parentData['title'], sprintf($zlink, $parentData['id']));
        }
    }
    $ret[] = l($node->title, sprintf($nlink, $node->id));
    $ret[count($ret) - 1] = '<b>' . $ret[count($ret) - 1] . '</b>';
    $child = array();
    $query = db_query('SELECT d.id, d.nick, d.type ' . 'FROM {guifi_devices} d ' . 'WHERE d.nid = %d ' . 'ORDER BY d.id DESC', $node->id);
    $c = 0;
    while ($dChild = db_fetch_array($query) and $c <= 10) {
        $child[] = l($dChild['nick'], sprintf($dlink, $dChild['id']), array('attributes' => array('title' => $dChild['type'])));
        $c++;
    }
    if ($c >= 10) {
        $child[] = l(t('more...'), 'node/' . $node->id . '/view/devices');
    }
    if (count($child)) {
        $child[0] = '<br /><small>(' . $child[0];
        $child[count($child) - 1] = $child[count($child) - 1] . ')</small>';
        $ret = array_merge($ret, $child);
    }
    return $ret;
}
function guifi_ipcalc_get_subnet_by_nid($nid, $mask_allocate = '255.255.255.224', $network_type = 'public', $ips_allocated = NULL, $allocate = 'No', $verbose = FALSE)
{
    if (empty($nid)) {
        drupal_set_message(t('Error: trying to search for a network for unknown node or zone'), 'error');
        return;
    }
    if (empty($mask_allocate)) {
        drupal_set_message(t('Error: trying to search for a network of unknown size'), 'error');
        return;
    }
    if (empty($network_type)) {
        drupal_set_message(t('Error: trying to search for a network for unknown type'), 'error');
        return;
    }
    // print "Going to allocate network ".$mask_allocate."-".$network_type;
    global $user;
    $tbegin = microtime(TRUE);
    $zone = node_load(array('nid' => $nid));
    if ($zone->type == 'guifi_node') {
        $zone = guifi_zone_load($zone->zone_id);
    }
    $rzone = $zone;
    $depth = 0;
    $root_zone = $zone->id;
    $lbegin = microtime(TRUE);
    $search_mask = $mask_allocate;
    do {
        // while next is not the master, check within the already allocated ranges
        $result = db_query('SELECT n.id, n.base, n.mask ' . 'FROM {guifi_networks} n ' . 'WHERE n.zone = "%s" ' . '  AND network_type="%s" ' . 'ORDER BY n.id', $zone->id, $network_type);
        if ($verbose) {
            drupal_set_message(t('Searching if %mask is available at %zone, elapsed: %secs', array('%mask' => $mask_allocate, '%zone' => $zone->title, '%secs' => round(microtime(TRUE) - $lbegin, 4))));
        }
        // if there are already networks defined, increase network mask, up to /20 level
        // here, getting the total # of nets defined
        $tnets = 0;
        while ($net = db_fetch_object($result)) {
            $tnets++;
            $item = _ipcalc($net->base, $net->mask);
            // if looking for mesh ip (255.255.255.255) base address & broadcast
            // should be considered as used
            if ($search_mask == '255.255.255.255') {
                $ips_allocated[ip2long($net->base)] = 32;
                $ips_allocated[ip2long($item['netend'])] = 32;
            }
            if ($ip = guifi_ipcalc_find_subnet($net->base, $net->mask, $mask_allocate, $ips_allocated)) {
                if ($verbose) {
                    drupal_set_message(t('Found %ip/%rmask available at %netbase/%amask, got from %zone, elapsed: %secs', array('%amask' => $net->mask, '%netbase' => $net->base, '%ip' => $ip, '%rmask' => guifi_ipcalc_get_maskbits($mask_allocate), '%zone' => $zone->title, '%secs' => round(microtime(TRUE) - $lbegin, 4))));
                }
                // reserve the available range fount into database?
                if ($depth and ($allocate == 'Yes' and $network_type == 'public' and $mask_allocate != '255.255.255.255')) {
                    $msg = strip_tags(t('A new network (%base / %mask) has been allocated for zone %name, got from %name2 by %user.', array('%base' => $ip, '%mask' => $mask_allocate, '%name' => $rzone->title, '%name2' => $zone->title, '%user' => $user->name)));
                    $to_mail = explode(',', $rzone->notification);
                    $to_mail = explode(',', $zone->notification);
                    $nnet = array('new' => TRUE, 'base' => $ip, 'mask' => $mask_allocate, 'zone' => $root_zone, 'newtwork_type' => $network_type);
                    $nnet = _guifi_db_sql('guifi_networks', NULL, $nnet, $log, $to_mail);
                    guifi_notify($to_mail, $msg, $log);
                    drupal_set_message($msg);
                    if ($search_mask == '255.255.255.255') {
                        $ip = long2ip(ip2long($ip) + 1);
                    }
                }
                return $ip;
            }
        }
        // while there is a network defined at the zone
        // Network was not allocated
        if ($verbose) {
            drupal_set_message(t('Unable to find space at %zone, will look at parents, elapsed: %secs', array('%zone' => $zone->title, '%secs' => round(microtime(TRUE) - $lbegin, 4))));
        }
        // Need for an unused range,
        // already allocated networks from others than parents should be considered
        // as allocated ips (skipped)
        // This have to be done once, so do if is the zone being asked for
        if ($root_zone == $zone->id) {
            $parents = guifi_zone_get_parents($root_zone);
            $query = db_query('SELECT base ipv4, mask ' . 'FROM {guifi_networks} ' . 'WHERE zone NOT IN (' . implode(',', guifi_zone_get_parents($root_zone)) . ')');
            while ($nip = db_fetch_array($query)) {
                $ips_allocated[ip2long($nip['ipv4']) + 1] = guifi_ipcalc_get_maskbits($nip['mask']);
            }
            // once merged, sort
            ksort($ips_allocated);
            // calculating the needed mask
            if ($network_type == 'public') {
                $depth++;
                if ($tnets > 0 and $tnets < 5) {
                    // between 1 and 4, 24 - nets defined
                    $maskbits = 24 - $tnets;
                } else {
                    if ($tnets >= 5) {
                        // greater than 4, /20 - 255.255.240.0
                        $maskbits = 20;
                    } else {
                        // first net, /24 - 255.255.255.0
                        $maskbits = 24;
                    }
                }
                $mitem = _ipcalc_by_netbits($net->base, $maskbits);
                $mbits_allocate = guifi_ipcalc_get_maskbits($mask_allocate);
                if ($mbits_allocate > $maskbits or $mask_allocate == '255.255.255.255') {
                    $mask_allocate = $mitem['netmask'];
                }
            }
        }
        // Take a look at the parent network zones
        $master = $zone->master;
        if ($zone->master > 0) {
            $zone = guifi_zone_load($zone->master);
        }
    } while ($master > 0);
    return FALSE;
}
function budgets_supplier_list_by_zone($zone, $params = NULL)
{
    guifi_log(GUIFILOG_TRACE, 'budgets_supplier_list_by_zone (PARAMS)', $params);
    $zroot = guifi_bg_zone_root();
    $vars = array();
    if ($zone->id == 0 or empty($zone->id)) {
        $zone->id = $zroot;
    }
    if ($params) {
        $p = explode(',', $params);
        foreach ($p as $v) {
            $v = explode('=', $v);
            if (!empty($v[1])) {
                $vars[$v[0]] = explode('|', $v[1]);
            }
        }
    }
    $output = drupal_get_form('budgets_supplier_list_by_zone_filter', $zone->id, $vars);
    $parents = array();
    if ($zone->id == $zroot) {
        // listing root zone: don't have to list the parents or childs'
        $where = '';
        //list all
    } else {
        guifi_log(GUIFILOG_TRACE, 'list_by_zone (zones)', guifi_zone_get_parents($zone->id));
        // other zones, parents and childs should be included, but
        // excluding root
        $zlist = array_diff(guifi_zone_childs_and_parents($zone->id), array(0, $zroot));
        $where = 'AND (s.zone_id IN (' . implode(',', $zlist) . ') ';
        foreach ($zlist as $z) {
            $where .= "OR CONCAT(',',s.zones,',') LIKE '%," . $z . ",%' ";
        }
        $where .= ') ';
    }
    guifi_log(GUIFILOG_TRACE, 'list_suppliers_by_zone (zones)', $vars);
    $svars = array();
    foreach ($vars as $k => $v) {
        foreach ($v as $p) {
            if (!empty($p)) {
                if ($k == 'title') {
                    $par = explode('-', $p);
                    if (count($par) > 1 and is_numeric($par[0])) {
                        $svars[] = " s.id = " . $par[0];
                    } else {
                        $svars[] = "upper(s.title) like '%" . strtoupper($p) . "%' ";
                    }
                } else {
                    $svars[] = $k . " LIKE '%" . $p . "%' ";
                }
            }
        }
    }
    if (count($svars) > 0) {
        $swhere = ' AND (' . implode(' AND ', $svars) . ') ';
    } else {
        $swhere = '';
    }
    $qquery = 'SELECT s.id ' . 'FROM {supplier} s, {node} n ' . 'WHERE s.id=n.nid ' . ' AND n.status=1 ' . $swhere . $where . 'ORDER BY ' . '  REPLACE(' . '    REPLACE(' . '      IF(' . '        LENGTH(TRIM(s.official_rating)=2),' . '        CONCAT(TRIM(s.official_rating),"1"),' . '        s.official_rating),' . '      "-",2),' . '    "+","0"),' . ' role, rand() ';
    guifi_log(GUIFILOG_TRACE, 'list_by_zone (suppliers query)', $qquery);
    $pager = pager_query($qquery, 50);
    // $output = '';
    while ($s = db_fetch_object($pager)) {
        $supplier = node_load(array('nid' => $s->id));
        $output .= node_view($supplier, TRUE, FALSE, TRUE);
    }
    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
    drupal_set_breadcrumb(guifi_zone_ariadna($zone->id, 'node/%d/suppliers'));
    //  $output .= theme_pager(NULL, variable_get("guifi_pagelimit", 50));
    //  $node = node_load(array('nid' => $zone->id));
    //  $output .= theme_links(module_invoke_all('link', 'node', $node, FALSE));
    print theme('page', $output, FALSE);
    return;
}
function guifi_ipv4_print_data($zone, $list = 'parents', $ips_allocated)
{
    global $user;
    $header = array(array('data' => t('network')), t('start / end'), array('data' => t('hosts'), 'style' => 'text-align: right;'), t('type'), t('min / max'), array('data' => t('ips used'), 'style' => 'text-align: right;'), array('data' => t('used %'), 'style' => 'text-align: right;'));
    if (user_access('administer guifi networks')) {
        $header = array_merge($header, array(t('operations')));
    }
    if ($list == 'childs') {
        $zones = guifi_zone_childs($zone->id);
        $pager = 1;
        $k = array_search($zone->id, $zones);
        unset($zones[$k]);
    } else {
        $zones = guifi_zone_get_parents($zone->id);
        $pager = 0;
    }
    if (empty($zones)) {
        return t('There is no zones to look at');
    }
    $sql = 'SELECT
            zone, id, base, mask, network_type
          FROM {guifi_networks}
          WHERE zone IN (' . implode(',', $zones) . ')
          ORDER BY FIND_IN_SET(zone,"' . implode(',', $zones) . '")';
    $rows = array();
    $result = pager_query($sql, variable_get('guifi_pagelimit', 10));
    $current_zoneid = -1;
    while ($net = db_fetch_object($result)) {
        $item = _ipcalc($net->base, $net->mask);
        // obtaing the used ip's
        $min = ip2long($item['netstart']);
        $max = ip2long($item['netend']);
        $ips = 0;
        $k = $min;
        $amin = NULL;
        $amax = NULL;
        while ($k <= $max) {
            if (isset($ips_allocated[$k])) {
                $ips++;
                $amax = $k;
                if ($ips == 1) {
                    $amin = $k;
                }
            }
            $k++;
        }
        if ($current_zoneid != $net->zone) {
            $current_zoneid = $net->zone;
            $rows[] = array(array('data' => l(guifi_get_zone_name($net->zone), 'node/' . $net->zone . '/view/ipv4'), 'colspan' => '0'));
        }
        $row = array($net->base . '/' . $item['maskbits'] . ' (' . $net->mask . ')', $item['netstart'] . ' / ' . $item['netend'], array('data' => number_format($item['hosts']), 'align' => 'right'), $net->network_type, long2ip($amin) . ' / ' . long2ip($amax), array('data' => number_format($ips), 'align' => 'right'), array('data' => round($ips * 100 / $item['hosts']) . '%', 'align' => 'right'));
        if (user_access('administer guifi networks')) {
            $row[] = array('data' => l(guifi_img_icon('edit.png'), 'guifi/ipv4/' . $net->id . '/edit', array('html' => TRUE, 'title' => t('edit network'), 'attributes' => array('target' => '_blank'))) . l(guifi_img_icon('drop.png'), 'guifi/ipv4/' . $net->id . '/delete', array('html' => TRUE, 'title' => t('delete device'), 'attributes' => array('target' => '_blank'))), 'align' => 'center');
        }
        $rows[] = $row;
    }
    if (count($rows)) {
        $output .= theme('table', $header, $rows);
        $output .= theme('pager', NULL, variable_get('guifi_pagelimit', 10));
    } else {
        $output .= t('None');
    }
    return $output;
}
function guifi_zone_childs_and_parents($zid)
{
    return array_merge(guifi_zone_childs($zid), guifi_zone_get_parents($zid));
}