Location: PHPKode > scripts > Schedule > schedule/class.schedule.php
<?php
  /**
   * Schedule
   * Class to create schedule images with the help of a XML file
   *
   * @author  Jeph <hide@address.com>
   * @license GNU General Public License
   * @package Schedule
   * @version 0.1
   * @url     <none>
   **/
  class Schedule
  {
    /**
     * Schedule::width
     * Image width
     *
     * @access public
     * @var    integer
     **/
    var $width = 700;

    /**
     * Schedule::height
     * Image height
     *
     * @access public
     * @var    integer
     **/
    var $height = 300;

    /**
     * Schedule::bg
     * Background settings (color)
     *
     * @access public
     * @var    array
     **/
    var $bg = array();

    /**
     * Schedule::grid
     * Grid settings (color)
     *
     * @access public
     * @var    array
     **/
    var $grid = array();
    
    /**
     * Schedule::schedule
     * Schedule settings (color)
     *
     * @access public
     * @var    array
     **/
    var $schedule = array();
    
    /**
     * Schedule::legend
     * Legend settings (color, font, padding)
     *
     * @access public
     * @var    array
     **/
    var $legend = array();
    
    /**
     * Schedule::block
     * Block settings (color, font, padding, alpha)
     *
     * @access public
     * @var    array
     **/
    var $block = array();

    /**
     * Schedule::struct
     * XML struct
     *
     * @access private
     * @var    array
     **/
    var $struct = array();
    
    /**
     * Schedule::im
     * Image resource
     *
     * @access private
     * @var    resource
     **/
    var $im;

    /**
     * Schedule::Schedule()
     * Class constructor (can load a $xml data/file)
     *
     * @param string  $xml  XML file or data
     * @param boolean $file Indicates whether $xml is a file or not (data)
     **/
    function Schedule($xml = '', $file = true)
    {
      // default settings
      $this->bg['color']   = array(255, 255, 255);
      $this->grid['color'] = array(180, 180, 180);
      $this->schedule['color'] = array(250, 250, 250);
      $this->block['padding_left'] = 3;
      $this->block['padding_top'] = 3;
      $this->block['font_title'] = 3;
      $this->block['font_description'] = 2;
      $this->block['color_border'] = array(250, 230, 180);
      $this->block['color_bg'] = array(220, 200, 150);
      $this->block['color_title'] = array(150, 150, 150);
      $this->block['color_description'] = array(150, 150, 150);
      $this->block['alpha'] = 50;
      $this->block['align_title'] = 'left';
      $this->block['align_description'] = 'left';
      $this->legend['color_bg'] = array(245, 245, 245);
      $this->legend['color_text'] = array(0, 0, 0);
      $this->legend['font'] = 2;
      $this->legend['padding_top'] = 20;
      $this->legend['padding_bottom'] = 0;
      $this->legend['padding_left'] = 50;
      $this->legend['padding_right'] = 0;
      
      if (strlen($xml) > 0)
      {
        if ($file) Schedule::LoadXmlFile($xml);
        else Schedule::LoadXmlData($xml);
      }
    }
    
    /**
     * Schedule::LoadXmlFile()
     * Load data from file
     *
     * @access public
     * @param  string $file Path to filename
     **/
    function LoadXmlFile($file)
    {
      if (($fp = @fopen($file, 'r')) !== false)
      {
        $content = '';
        while (!feof($fp)) $content .= fread($fp, 4096);
        fclose($fp);
        
        return Schedule::LoadXmlData($content);
      }
      else return false;
    }
    
    /**
     * Schedule::LoadXmlData()
     * Parse data
     *
     * @access public
     * @param  string $data XML data
     **/
    function LoadXmlData($data)
    {
      $xml = new ScheduleXml($data);
      
      if (count($xml->struct) > 0)
      {
        $this->struct = $xml->struct;
        
        // clear unwanted tags
        foreach ($this->struct as $k => $struct)
        {
          if ($struct['tag'] != 'SCHEDULE') unset($this->struct[$k]);
          else
          {
            foreach ($struct['childs'] as $k2 => $child)
            {
              if ($child['tag'] != 'DAY' && $child['tag'] != 'SETTINGS')
              {
                unset($this->struct[$k]['childs'][$k2]);
              }
              elseif ($child['tag'] == 'DAY')
              {
                foreach ($child['childs'] as $k3 => $block)
                {
                  if ($block['tag'] != 'BLOCK')
                  {
                    unset($this->struct[$k]['childs'][$k2]['childs'][$k3]);
                  }
                }
                $this->ReorganizeArray($this->struct[$k]['childs'][$k2]['childs']);
              }
            }
            $this->ReorganizeArray($this->struct[$k]['childs']);
          }
        }
        $this->ReorganizeArray($this->struct);
        return true;
      }
      else return false;
    }
    
    /**
     * Schedule::Draw()
     * Draw schedule
     *
     * @access public
     * @param  string  $output_file File to output
     * @param  integer $schedule    Schedule pointer (usualy 0)
     **/
    function Draw($output_file = '', $schedule = 0)
    {
      $this->im = imagecreatetruecolor($this->width, $this->height);
      
      // check settings
      for ($i = 0; $i < count($this->struct); $i++)
      {
        if ($this->struct[$i]['tag'] == 'SCHEDULE')
        {
          for ($j = 0; $j < count($this->struct[$i]['childs']); $j++)
          {
            if ($this->struct[$i]['childs'][$j]['tag'] == 'SETTINGS')
            {
              $this->UpdateSettings($this->struct[$i]['childs'][$j]['childs']);
            }
          }
        }
      }
      
      $this->DrawBackground();
      $this->DrawGrid($schedule);
      $this->DrawDays($schedule);
      
      if (is_dir(dirname($output_file)))
      {
        // save image
        imagepng($this->im, $output_file);
      }
      else
      {
        // output
        header('Content-Type: image/png');
        imagepng($this->im);
      }
      imagedestroy($this->im);
    }
    
    /**
     * Schedule::DrawBackground()
     * Draw schedule background
     *
     * @access private
     **/
    function DrawBackground()
    {
      $this->AllocateColor('im_bg_color', $this->bg['color']);
      imagefilledrectangle($this->im, 0, 0, $this->width, $this->height, $this->im_bg_color);
    }
    
    /**
     * Schedule::DrawGrid()
     * Draw schedule grid according to schedule pointer
     *
     * @access private
     * @param  integer $schedule Schedule pointer
     **/
    function DrawGrid($schedule)
    {
      $this->block_names = explode(',', $this->struct[$schedule]['attrib']['BLOCKS']);
      $this->day_names = explode(',', $this->struct[$schedule]['attrib']['DAYS']);
      $this->horiz_steps = count($this->block_names);
      $this->vert_steps = count($this->day_names);
      $this->horiz_stepsize = ($this->height - $this->legend['padding_top'] - $this->legend['padding_bottom']) / $this->horiz_steps;
      $this->vert_stepsize = ($this->width - $this->legend['padding_left'] - $this->legend['padding_right']) / $this->vert_steps;
      
      // legend & schedule bg
      $this->AllocateColor('im_legend_color_bg', $this->legend['color_bg']);
      $this->AllocateColor('im_grid_color', $this->grid['color']);

      $x1 = $this->legend['padding_left'];
      $x2 = $this->width - 1 - $this->legend['padding_right'];
      $y1 = $this->legend['padding_top'];
      $y2 = $this->height - 1 - $this->legend['padding_bottom'];
      if ($this->legend['padding_top'] > 0)
      {
        $this->DrawRectangle($x1, 0, $x2, $this->legend['padding_top'], $this->im_grid_color, $this->im_legend_color_bg);
      }
      if ($this->legend['padding_bottom'] > 0)
      {
        $this->DrawRectangle($x1, $this->height - 1 - $this->legend['padding_bottom'], $x2, $this->height - 1, $this->im_grid_color, $this->im_legend_color_bg);
      }
      if ($this->legend['padding_left'] > 0)
      {
        $this->DrawRectangle(0, $y1, $this->legend['padding_left'], $y2, $this->im_grid_color, $this->im_legend_color_bg);
      }
      if ($this->legend['padding_right'] > 0)
      {
        $this->DrawRectangle($this->width - 1 - $this->legend['padding_right'], $y1, $this->width - 1, $y2, $this->im_grid_color, $this->im_legend_color_bg);
      }

      $this->AllocateColor('im_schedule_color_bg', $this->schedule['color']);
      $this->DrawRectangle($x1, $y1, $x2, $y2, $this->im_grid_color, $this->im_schedule_color_bg);


      $this->AllocateColor('im_legend_color_text', $this->legend['color_text']);
      
      // horizontal lines
      $offset = ceil($this->legend['padding_left'] / 2);
      $offset2 = $this->width - 1 - round($this->legend['padding_right'] / 2);
      for ($i = 0; $i < $this->horiz_steps; $i++)
      {
        if ($i < $this->horiz_steps)
        {
          $p = $this->legend['padding_top'] + round($i * $this->horiz_stepsize);
          imageline($this->im, 0, $p, $this->width, $p, $this->im_grid_color);
        }
        if ($this->legend['padding_left'] > 0)
        {
          $this->DrawText($offset, $this->legend['padding_top'] + round(($i + .5) * $this->horiz_stepsize), $this->legend['font'], $this->block_names[$i], $this->im_legend_color_text);
        }
        if ($this->legend['padding_right'] > 0)
        {
          $this->DrawText($offset2, $this->legend['padding_top'] + round(($i + .5) * $this->horiz_stepsize), $this->legend['font'], $this->block_names[$i], $this->im_legend_color_text);
        }
      }

      // vertical lines
      $offset = round($this->legend['padding_top'] / 2);
      $offset2 = $this->height - 1 - round($this->legend['padding_bottom'] / 2);
      for ($i = 0; $i < $this->vert_steps; $i++)
      {
        if ($i < $this->vert_steps)
        {
          $p = $this->legend['padding_left'] + round($i * $this->vert_stepsize);
          imageline($this->im, $p, 0, $p, $this->height, $this->im_grid_color);
        }
        if ($this->legend['padding_top'] > 0)
        {
          $this->DrawText($this->legend['padding_left'] + round(($i + .5) * $this->vert_stepsize), $offset, $this->legend['font'], $this->day_names[$i], $this->im_legend_color_text);
        }
        if ($this->legend['padding_bottom'] > 0)
        {
          $this->DrawText($this->legend['padding_left'] + round(($i + .5) * $this->vert_stepsize), $offset2, $this->legend['font'], $this->day_names[$i], $this->im_legend_color_text);
        }
      }
    }
    
    /**
     * Schedule::DrawDays()
     * Draw schedule blocks for all days given the schedule pointer
     *
     * @access private
     * @param  integer $schedule Schedule pointer
     **/
    function DrawDays($schedule)
    {
      $day = &$this->struct[$schedule]['childs'];
      $max = count($this->day_names);
      $maxblocks = count($this->block_names);
      for ($i = 0; $i < count($day); $i++)
      {
        if ($day[$i]['tag'] == 'DAY')
        {
          $this->DrawBlocks($day[$i]['attrib']['NUMBER'] - 1, $day[$i]['childs'], $max, $maxblocks);
        }
      }
    }

    /**
     * Schedule::UpdateSettings()
     * Updates settings from xml array
     *
     * @access private
     * @param  array   $settings Settings array
     **/
    function UpdateSettings(&$settings)
    {
      for ($i = 0; $i < count($settings); $i++)
      {
        if (in_array(strtolower($settings[$i]['tag']), array('block', 'legend', 'grid', 'schedule', 'bg')))
        {
          $this->UpdatePartSettings($settings[$i], strtolower($settings[$i]['tag']));
        }
      }
    }

    /**
     * Schedule::UpdatePartSettings()
     * Updates settings to a part of the schedule class (block, legend, ..)
     *
     * @access private
     * @param  array   $settings      Settings array
     * @param  string  $settings_part Settings section (block, legend, ..)
     **/
    function UpdatePartSettings(&$settings, $settings_part = 'block')
    {
      /*
       * general settings
       * all this IFs statements are to avoid error when display_errors = On
       * (thanks to Guido Fischer)
       */
      $general = $settings['attrib'];
      if (isset($general['BORDERCOLOR']))
        $this->SetVar($settings_part, $this->GetColor($general['BORDERCOLOR']), 'color_border');
      if (isset($general['BGCOLOR']))
        $this->SetVar($settings_part, $this->GetColor($general['BGCOLOR']), 'color_bg');
      if (isset($general['COLOR']))
        $this->SetVar($settings_part, $this->GetColor($general['COLOR']), 'color');
      if (isset($general['FONT']))
        $this->SetVar($settings_part, $general['FONT'], 'font');
      if (isset($general['LEFTPADDING']))
        $this->SetVar($settings_part, $general['LEFTPADDING'], 'padding_left');
      if (isset($general['TOPPADDING']))
        $this->SetVar($settings_part, $general['TOPPADDING'], 'padding_top');
      if (isset($general['RIGHTPADDING']))
        $this->SetVar($settings_part, $general['RIGHTPADDING'], 'padding_right');
      if (isset($general['BOTTOMPADDING']))
        $this->SetVar($settings_part, $general['BOTTOMPADDING'], 'padding_bottom');
      if (isset($general['ALPHA']))
        $this->SetVar($settings_part, $this->GetPercent($general['ALPHA'], 127), 'alpha');

      // child settings
      for ($i = 0; $i < count($settings['childs']); $i++)
      {
        switch ($settings['childs'][$i]['tag'])
        {
          case 'TITLE':
            $this->SetVar($settings_part, $this->GetColor($settings['childs'][$i]['attrib']['COLOR']), 'color_title');
            $this->SetVar($settings_part, $settings['childs'][$i]['attrib']['FONT'], 'font_title');
            $this->SetVar($settings_part, $this->GetAlign($settings['childs'][$i]['attrib']['ALIGN'], array('left', 'center', 'right')), 'align_title');
            break;
          case 'DESCRIPTION':
            $this->SetVar($settings_part, $this->GetColor($settings['childs'][$i]['attrib']['COLOR']), 'color_description');
            $this->SetVar($settings_part, $settings['childs'][$i]['attrib']['FONT'], 'font_description');
            $this->SetVar($settings_part, $this->GetAlign($settings['childs'][$i]['attrib']['ALIGN'], array('left', 'center', 'right')), 'align_description');
       }
      }
    }

    /**
     * Schedule::SetVar()
     * Sets (depending on value) a variable or array position (given a key)
     *
     * @access private
     * @param  string  $varname   Variable name
     * @param  mixed   $setting   Setting value
     * @param  string  $array_key Array key (for $this->varname)
     **/
    function SetVar($varname, $setting, $array_key = '')
    {
      // debug
      // echo "VAR:'{$varname}' SETTING:'{$setting}' KEY:'{$array_key}'<br>\n";
      if (is_array($setting))
      {
        if (count($setting) > 0)
        {
          if ($array_key != '') $this->{$varname}[$array_key] = $setting;
          else $this->$varname = $setting;
        }
      }
      elseif (strlen($setting) > 0 || is_numeric($setting))
      {
        if ($array_key != '') $this->{$varname}[$array_key] = $setting;
        else $this->$varname = $setting;
      }
    }

    /**
     * Schedule::DrawBlocks()
     * Draw a group of blocks in a given day
     *
     * @access private
     * @param  integer $day       Day where blocks should be drawed
     * @param  array   $blocks    Array containing all blocks
     * @param  integer $maxdays   Total days of the schedule
     * @param  integer $maxblocks Total blocks of the schedule
     **/
    function DrawBlocks($day, $blocks, $maxdays, $maxblocks)
    {
      for ($i = 0; $i < count($blocks); $i++)
      {
        $block = $blocks[$i]['attrib'];
        if (!isset($block['AT'])) $block['AT'] = 1;
        if (!isset($block['DAYSPAN'])) $block['DAYSPAN'] = 0;
        if (!isset($block['BLOCKSPAN'])) $block['BLOCKSPAN'] = 0;
        if (!isset($block['DAYOFFSET'])) $block['DAYOFFSET'] = 0;
        if (!isset($block['BLOCKOFFSET'])) $block['BLOCKOFFSET'] = 0;
        list($x1, $y1, $x2, $y2) = $this->GetCoords($day,
                                                    (int) ($block['AT'] - 1),
                                                    $block['DAYSPAN'],
                                                    $block['BLOCKSPAN'],
                                                    $maxdays,
                                                    $maxblocks,
                                                    $block['DAYOFFSET'],
                                                    $block['BLOCKOFFSET']);

        $block_settings = $this->block;
        $this->UpdatePartSettings($blocks[$i]);
        
        $this->AllocateColor('im_block_color_border', $this->block['color_border'], $this->block['alpha']);
        $this->AllocateColor('im_block_color_bg', $this->block['color_bg'], $this->block['alpha']);

        $this->DrawRectangle($x1 + 1, $y1 + 1, $x2 - 1, $y2 - 1, $this->im_block_color_border, $this->im_block_color_bg);

        if (!isset($this->im_block_color_title))
        {
          $this->AllocateColor('im_block_color_title', $this->block['color_title']);
        }
        
        // block title
        switch ($this->block['align_title'])
        {
          case 'center':
            $x = $x1 + round(($x2 - $x1) / 2);
            $y = $y1 + $this->block['padding_top'];
            break;
          case 'right':
            $x = $x2 - $this->block['padding_left'];
            $y = $y1 + $this->block['padding_top'];
            break;
          default: // left
            $x = $x1 + $this->block['padding_left'];
            $y = $y1 + $this->block['padding_top'];
            $this->block['align_title'] = 'left';
        }
        $this->DrawText($x, $y,
                        $this->block['font_title'],
                        $block['NAME'],
                        $this->im_block_color_title,
                        $this->block['align_title'],
                        'top');

        // block description
        if (strlen($blocks[$i]['data']) > 0)
        {
          if (!isset($this->im_block_color_description))
          {
            $this->AllocateColor('im_block_color_description', $this->block['color_description']);
          }

          $this->DrawDescription($x1 + $this->block['padding_left'],
                                 $y1 + $this->block['padding_top']
                                 + imagefontheight($this->block['font_title']) + 1,
                                 $x2 - $this->block['padding_left'],
                                 $y2 - $this->block['padding_top'],
                                 $this->block['font_description'],
                                 str_replace('\n', "\n", $blocks[$i]['data']),
                                 $this->im_block_color_description,
                                 $this->block['align_description']);
        }
        $this->block = $block_settings;
      }
    }
    
    /**
     * Schedule::GetPercent()
     * Given a string and the max value to 100%, it will return the
     * value corresponding to that percentage
     * e.g.: GetPercent('25%', 40) = 10
     *
     * @access private
     * @param  string  $string String containing a percentage
     * @param  integer $max    Value corresponding to 100%
     * @return integer
     **/
    function GetPercent($string, $max)
    {
      if (substr($string, -1, 1) == '%') $string = substr($string, 0, -1);
      if (is_numeric($string)) return round($string * $max / 100);
      else return '';
    }
    
    /**
     * Schedule::GetColor()
     * Transforms an hex RGB string into a PHP RGB array
     *
     * @access private
     * @param  string  $string String containing the color in hex RGB format
     * @return array
     **/
    function GetColor($string)
    {
      if ($string[0] == '#') $string = substr($string, 1);
      switch (strlen($string))
      {
        case 6: // common #rrggbb
          return array(hexdec(substr($string, 0, 2)), hexdec(substr($string, 2, 2)), hexdec(substr($string, 4)));
        case 3: // #rgb
          return array(hexdec($string[0] . $string[0]), hexdec($string[1] . $string[1]), hexdec($string[2] . $string[2]));
        case 1: // gray scale
          $v = hexdec($string . $string);
          return array($v, $v, $v);
        default:
          return array();
      }
    }

    /**
     * Schedule::GetCoords()
     * Returns coordinates of the 4 corners of a block to draw in the image
     *
     * @access private
     * @param  integer $x        X
     * @param  integer $y        Y
     * @param  integer $x_span   X expansion (to other days)
     * @param  integer $y_span   Y expansion (to other blocks)
     * @param  integer $x_max    Total X (total days)
     * @param  integer $y_max    Total Y (total blocks)
     * @param  integer $x_offset X offset
     * @param  integer $y_offset Y offset
     * @return array
     **/
    function GetCoords($x, $y, $x_span, $y_span, $x_max, $y_max, $x_offset, $y_offset)
    {
      $newx = $this->legend['padding_left'] + round(($x + $x_offset) * $this->vert_stepsize);
      $newy = $this->legend['padding_top'] + round(($y + $y_offset) * $this->horiz_stepsize);
      if (($x + $x_span + 1) >= $x_max) $x2 = $this->width - 1 - $this->legend['padding_right'];
      else $x2 = $this->legend['padding_left'] + round($this->vert_stepsize * ($x + $x_offset + $x_span + 1));
      if (($y + $y_span + 1) >= $y_max) $y2 = $this->height - 1 - $this->legend['padding_bottom'];
      else $y2 = $this->legend['padding_top'] + round($this->horiz_stepsize * ($y + $y_offset + $y_span + 1));
      return array($newx, $newy, $x2, $y2);
    }
    
    /**
     * Schedule::GetAlign()
     * Returns the align if it's valid or the first valid align
     *
     * @access private
     * @param  string  $align           String containing the desired align
     * @param  array   $possible_aligns Array containing all the possible aligns
     * @return string
     **/
    function GetAlign($align, $possible_aligns)
    {
      if (in_array(strtolower($align), $possible_aligns)) return strtolower($align);
      else return $possible_aligns[0];
    }

    /**
     * Schedule::DrawDescription()
     * Draws the description of a block given the 4 corners of the
     * block and some more settings
     *
     * @access private
     * @param  integer $x1    X of top left corner
     * @param  integer $y1    Y of top left corner
     * @param  integer $x2    X of bottom right corner
     * @param  integer $y2    Y of bottom right corner
     * @param  integer $font  Font
     * @param  string  $text  Text to draw
     * @param  integer $color Color
     * @param  string  $align Alignment (default is left)
     **/
    function DrawDescription($x1, $y1, $x2, $y2, $font, $text, $color, $align = 'left')
    {
      $lineheight = imagefontheight($font) + 1;
      $maxy = ($y2 - $lineheight);
      $linemaxchars = floor(($x2 - $x1) / imagefontwidth($font));
      $text = explode("\n", $text);
      for ($i = 0; $i < count($text); $i++)
      {
        while ($y1 <= $maxy && strlen($text[$i]) > 0)
        {
          $s = substr($text[$i], 0, $linemaxchars + 1);
          if (strlen($text[$i]) >= $linemaxchars)
          {
            $p = strrpos($s, ' ');
            if ($p !== false)
            {
              $s = substr($s, 0, $p);
              $text[$i] = substr($text[$i], $p + 1);
            }
            else
            {
              $s = substr($text[$i], 0, $linemaxchars);
              $text[$i] = substr($text[$i], $linemaxchars);
            }
          }
          else $text[$i] = '';

          switch ($align)
          {
            case 'center':
              $this->DrawText($x1 + round(($x2 - $x1) / 2), $y1, $font, $s, $color, $align, 'top');
              break;
            case 'right':
              $this->DrawText($x1, $y1, $font, $s, $color, $align, 'top');
              break;
            default:
              $this->DrawText($x1, $y1, $font, $s, $color, $align, 'top');
          }
          $y1 += $lineheight;
        }
      }
    }
    
    /**
     * Schedule::DrawText()
     * Draw text given (x,y) points, font, color, horizontal and
     * vertical align
     *
     * @access private
     * @param  integer $x      X
     * @param  integer $y      Y
     * @param  integer $font   Font
     * @param  string  $text   Text to draw
     * @param  integer $color  Color
     * @param  string  $align  Horizontal alignment (default is center)
     * @param  string  $valign Vertical alignment (default is middle)
     **/
    function DrawText($x, $y, $font, $text, $color, $align = 'center', $valign = 'middle')
    {
      $width = strlen($text) * imagefontwidth($font);
      if ($align == 'right') $x -= $width;
      elseif ($align == 'center') $x -= round($width / 2);
      if ($valign == 'bottom') $y -= imagefontheight($font);
      elseif ($valign == 'middle') $y -= round(imagefontheight($font) / 2);
      imagestring($this->im, $font, $x, $y, $text, $color);
    }
    
    /**
     * Schedule::DrawRectangle()
     * Draws a rectangle given the 4 corner points, border and
     * background color
     *
     * @access private
     * @param  integer $x1          X of top left corner
     * @param  integer $y1          Y of top left corner
     * @param  integer $x2          X of bottom right corner
     * @param  integer $y2          Y of bottom right corner
     * @param  integer $bordercolor Border color
     * @param  integer $bgcolor     Background color
     **/
    function DrawRectangle($x1, $y1, $x2, $y2, $bordercolor, $bgcolor)
    {
      imagefilledrectangle($this->im, $x1, $y1, $x2, $y2, $bgcolor);
      imagerectangle($this->im, $x1, $y1, $x2, $y2, $bordercolor);
    }
    
    /**
     * Schedule::AllocateColor()
     * Allocates a color (if needed) and sets a variable with the
     * index of that color (alpha is added if possible [GD2])
     *
     * @access private
     * @param  string  $varname Variable name
     * @param  array   $color   Array containing RGB color
     * @param  integer $alpha   Transparency: (opaque) 0<->127 (transparent)
     **/
    function AllocateColor($varname, $color, $alpha = 0)
    {
      if (function_exists('imagecolorexactalpha'))
      {
        $c = imagecolorexactalpha($this->im, $color[0], $color[1], $color[2], $alpha);
        if ($c == -1)
        {
          $c = imagecolorallocatealpha($this->im, $color[0], $color[1], $color[2], $alpha);
        }
      }
      else
      {
        $c = imagecolorexact($this->im, $color[0], $color[1], $color[2]);
        if ($c == -1)
        {
          $c = imagecolorallocate($this->im, $color[0], $color[1], $color[2]);
        }
      }
      $this->$varname = $c;
    }
    
    /**
     * Schedule::ReorganizeArray()
     * Resets the indexes of an array
     *
     * @access private
     * @param  array   $array Array to reorganize
     **/
    function ReorganizeArray(&$array)
    {
      $arrk = array_keys($array);
      for ($i = 0; $i < count($arrk); $i++)
      {
        if ($i != $arrk[$i])
        {
          $array[$i] = $array[$arrk[$i]];
          unset($array[$arrk[$i]]);
        }
      }
    }
  }
  
  /**
   * ScheduleXml
   * Used by package Schedule to parse xml data
   *
   * @author  Jeph
   * @license GNU General Public License
   * @package Schedule
   * @version 0.1
   **/
  class ScheduleXml
  {
    /**
     * ScheduleXml::xml
     * XML parser reference
     *
     * @var resource
     **/
    var $xml;

    /**
     * ScheduleXml::lastnode
     * Array of references to every opened node in ScheduleXml::struct
     *
     * @var array
     **/
    var $lastnode = array();
    
    /**
     * ScheduleXml::struct
     * Array containing XML structure of XML data given
     *
     * @var array
     **/
    var $struct = array();

    /**
     * ScheduleXml::ScheduleXml()
     * Class constructor, parses data
     *
     * @param string $xml
     **/
    function ScheduleXml($xml)
    {
      $this->xml = xml_parser_create();
      xml_set_object($this->xml, $this);
      xml_set_element_handler($this->xml, 'tag_open', 'tag_close');
      xml_set_character_data_handler($this->xml, 'cdata');
      $this->lastnode = array(&$this->struct);
      xml_parse($this->xml, $xml);
      xml_parser_free($this->xml);
    }
    
    /**
     * ScheduleXml::tag_open()
     * Used by xml parser to return an open tag
     *
     * @access private
     * @param  resource $parser     Parser resource
     * @param  string   $tag        Tag found
     * @param  array    $attributes Tag attributes
     **/
    function tag_open($parser, $tag, $attributes)
    {
      $c = count($this->lastnode) - 1;
      // add node to array
      $this->lastnode[$c][] = array('tag'    => $tag, 'attrib' => $attributes,
                                    'data'   => '',   'childs' => array());
                                   
      // add reference
      $this->lastnode[] = &$this->lastnode[$c][count($this->lastnode[$c]) - 1]['childs'];
    }
    
    /**
     * ScheduleXml::tag_close()
     * Used by xml parser to return a closed tag
     *
     * @access private
     * @param  resource $parser Parser resource
     * @param  string   $tag    Tag found
     **/
    function tag_close($parser, $tag)
    {
      // remove last reference
      array_pop($this->lastnode);
    }
    
    /**
     * ScheduleXml::cdata()
     * Used by xml parser to return data inside a tag
     *
     * @access private
     * @param  resource $parser Parser resource
     * @param  string   $cdata  Tag data
     **/
    function cdata($parser, $cdata)
    {
      if (strlen(ltrim($cdata)) > 0)
      {
        $p = count($this->lastnode) - 2;
        $this->lastnode[$p][count($this->lastnode[$p]) - 1]['data'] .= ltrim($cdata);
      }
    }
  }
?>
Return current item: Schedule