| <?php
namespace GGG\Html\ChartBuilder;
class HtmlTable
{
  const CALCULATIONS_NS = '\\GGG\\Html\\ChartBuilder\\Calculations\\';
  protected $id;           // ''
  protected $data;         // [[#,…]|#,…]
  protected $html;         // ''
  protected $title;        // ''
  protected $headers;      // ['',…]
  protected $calc_data;    // [[#,…]|#,…]
  protected $calc_type;    // ''
  private $data_set;       // +|-
  private $title_set;      // +|-
  private $data_sizes;     // ['',…]
  private $headers_set;    // +|-
  private $calc_data_set;  // +|-
  private $is_responsive;  // +|-
  private $use_bootstrap;  // +|-
  
  public function __construct( $style = 0, $responsive = 0 )
  {
    $this->id = '';
    $this->data = [];
    $this->html = '';
    $this->title = '';
    $this->headers = [];
    $this->calc_data = [];
    $this->calc_type = [];
    $this->data_set = false;
    $this->title_set = false;
    $this->headers_set = false;
    $this->calc_data_set = false;
    if( 0 === intval( $style ) )
    {
      $this->use_bootstrap = false;
    }
    if( 1 === intval( $style ) )
    {
      $this->use_bootstrap = true;
    }
    if( 0 === intval( $responsive ) )
    {
      $this->is_responsive = false;
    }
    if( 1 === intval( $responsive ) )
    {
      $this->is_responsive = true;
    }
    return $this;
  }
  protected function setTitle( $title )
  {
    if( $this->title_set === false )
    {
      $this->title = ucwords( trim( $title ) );
      if( preg_match( '/^(.*\s.*)+$/i', $this->title ) )
      {
        $words = preg_split( '/\s+?/', lcfirst( $this->title ) );
        foreach( $words as $index => $word )
        {
          $this->id .= $word;
        }
      }
      else // true !== preg_match( '/^(.*\s.*)+$/i', $this->title )
      {
        $this->id .= lcfirst( $this->title );
      }
      $this->id .= 'Table';
      $this->title_set = true;
    }
    return $this;
  }
  protected function setHeaders( $headers )
  {
    if( $this->headers_set === false )
    {
      array_push( $this->headers, $headers );
      $this->headers_set = true;
    }
    return $this;
  }
  protected function setRowData( $data )
  {
    array_push( $this->data, $data );
    $this->data_set = true;
    return $this;
  }
  protected function total()
  {
    $calc_type = 'Total';
    $calc_type_class = static::CALCULATIONS_NS . $calc_type;
    $total = new $calc_type_class;
    array_push( $this->calc_type, $calc_type );
    array_push( $this->calc_data, $total->calc( $this->data ) );
    $this->calc_data_set = true;
    return $this;
  }
  protected function average()
  {
    $calc_type = 'Average';
    $calc_type_class = static::CALCULATIONS_NS . $calc_type;
    $average = new $calc_type_class;
    array_push( $this->calc_type, $calc_type );
    array_push( $this->calc_data, $average->calc( $this->data ) );
    $this->calc_data_set = true;
    return $this;
  }
  protected function difference()
  {
    $calc_type = 'Difference';
    $calc_type_class = static::CALCULATIONS_NS . $calc_type;
    $difference = new $calc_type_class;
    array_push( $this->calc_type, $calc_type );
    array_push( $this->calc_data, $difference->calc( $this->data ) );
    $this->calc_data_set = true;
    return $this;
  }
  protected function highest()
  {
    $calc_type = 'Highest';
    $calc_type_class = static::CALCULATIONS_NS . $calc_type;
    $highest = new $calc_type_class;
    array_push( $this->calc_type, $calc_type );
    array_push( $this->calc_data, $highest->calc( $this->data ) );
    $this->calc_data_set = true;
    return $this;
  }
  protected function lowest()
  {
    $calc_type = 'Lowest';
    $calc_type_class = static::CALCULATIONS_NS . $calc_type;
    $lowest = new $calc_type_class;
    array_push( $this->calc_type, $calc_type );
    array_push( $this->calc_data, $lowest->calc( $this->data ) );
    $this->calc_data_set = true;
    return $this;
  }
  protected function setup()
  {
    if( true === $this->checkForDataUniformity() )
    {
      $this->initializeSetup();
      if( $this->headers_set === true )
      {
        foreach( $this->headers as $data )
        {
          $this->insertHeadersRow( $data );
        }
      }
      if( $this->data_set === true )
      {
        foreach( $this->data as $row => $data )
        {
          $this->insertDataRow( $row, $data );
        }
        $this->closeDataRow();
      }
      if( $this->calc_data_set === true )
      {
        foreach( $this->calc_data as $row => $data )
        {
          $this->insertCalcDataRow( $row, $data );
        }
        $this->closeCalcDataRow();
      }
      return $this->finishSetup();
    }
  }
  private function checkForDataUniformity()
  {
    $headers_sizes = [
      'rows' => 0,
      'data' => []
    ];
    foreach( $this->headers as $rowI => $row )
    {
      $headers_sizes['rows'] = $rowI + 1;
      if( is_array( $row ) )
      {
        foreach( $row as $dataI => $data )
        {
array_push( $headers_sizes['data'], $data );
        }
      }
      else // false == is_array( $row )
      {
        array_push( $headers_sizes['data'], $row );
      }
    }
    $data_sizes = [
      'rows' => 0,
      'data' => []
    ];
    foreach( $this->data as $rowI => $row )
    {
      $data_sizes['rows'] = $rowI + 1;
      foreach( $row as $dataI => $data )
      {
        array_push( $data_sizes['data'], count( $data ) );
      }
    }
    $calc_data_sizes = [
      'rows' => 0,
      'data' => []
    ];
    foreach( $this->calc_data as $rowI => $row )
    {
      $calc_data_sizes['rows'] = $rowI + 1;
      foreach( $row as $dataI => $data )
      {
        array_push( $calc_data_sizes['data'], count( $data ) );
      }
    }
    $headers_size = count( $headers_sizes['data'] ) / $headers_sizes['rows'];
    $data_size = count( $data_sizes['data'] ) / $data_sizes['rows'];
    $calc_data_size = count( $calc_data_sizes['data'] ) / $calc_data_sizes['rows'];
    if( $headers_size != 0 && $data_size != 0 && $calc_data_size != 0 )
    {
      if( $headers_size === $data_size && $data_size === $calc_data_size && $calc_data_size === $headers_size )
      {
        $this->data_sizes = [
          'headers' => [
            'rows' => $headers_sizes['rows'],
            'cols' => $headers_size
          ],
          'data' => [
            'rows' => $data_sizes['rows'],
            'cols' => $data_size
          ],
          'calc_data' => [
            'rows' => $calc_data_sizes['rows'],
            'cols' => $calc_data_size
          ]
        ];
        return true;
      }
      else // $headers_size !== $data_size && $data_size !== $calc_data_size && $calc_data_size !== $headers_size
      {
        if( $headers_size !== $data_size )
        {
          echo 'The "$headers" [' . $headers_size . '] and "$data" [' . $data_size . '] data array sizes do not match one and other.';
        }
        if( $data_size !== $calc_data_size )
        {
          echo 'The "$data" [' . $data_size . '] and "$calc_data" [' . $calc_data_size . '] data array sizes do not match one and other.';
        }
        if( $calc_data_size !== $headers_size )
        {
          echo 'The "$calc_data" [' . $calc_data_size . '] and "$headers" [' . $headers_size . '] data array sizes do not match one and other.';
        }
      }
    }
    else // $headers_size == 0 && $data_size == 0 && $calc_data_size == 0
    {
      echo 'One or more data array sizes either (i) do not match the size of one or more of the others, or (ii) do not contain any data at all.';
    }
    return false;
  }
  private function initializeSetup()
  {
    if( $this->use_bootstrap === true )
    {
      $this->setupBootstrapTable();
    }
    else // $this->use_bootstrap !== true
    {
      $this->setupBasicTable();
    }
  }
  private function insertHeadersRow( $d )
  {
    if( $this->headers_set === true )
    {
      $row_index_header = '#';
      $ctx = ' style="border-top:1px solid #DDDDDD;border-right:1px solid #DDDDDD;border-bottom:2px solid #DDDDDD;border-left:1px solid #DDDDDD;"';
      $ctx2 = ' style="border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
      if( $this->calc_data_set === true )
      {
        if( $this->use_bootstrap === true )
        {
          $row_index_header = '#</b> <span class="text-muted">/</span> <b>=';
        }
        else
        {
          $row_index_header = '#</b> <span style="color:rgba(0,0,0,0.33);">/</span> <b>=';
        }
      }
      if( $this->use_bootstrap === true )
      {
        $ctx = NULL;
        $ctx2 = ' class="text-center"';
      }
      $this->html .=<<<EOH
        <thead>
          <tr{$ctx}>
            <th{$ctx2}>
              <b>{$row_index_header}</b>
            </th>
EOH;
      foreach( $d as $index => $header )
      {
        $header = ucwords( $header );
        $this->html .=<<<EOH
            <th{$ctx2}>
              <b>{$header}</b>
            </th>
EOH;
      }
      $this->html .=<<<EOH
          </tr>
        </thead>
EOH;
    }
  }
  private function insertDataRow( $r, $d )
  {
    $ctx = ' style="border:1px solid #DDDDDD;"';
    $ctx2 = ' style="border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
    if( $this->use_bootstrap === true )
    {
      $ctx = NULL;
      $ctx2 = ' class="text-center"';
    }
    if( $r === 0 )
    {
      if( $this->headers_set === true )
      {
        $this->html .=<<<EOH
        <tbody>
EOH;
      }
      else // $this->headers_set !== true
      {
        $this->html .=<<<EOH
      <tbody>
EOH;
      }
    }
    if( $this->headers_set === true )
    {
      $this->html .=<<<EOH
          <tr{$ctx}>
            <td{$ctx2}>
              {$r}
            </td>
EOH;
    }
    else // $this->headers_set !== true
    {
      $this->html .=<<<EOH
        <tr{$ctx}>
          <td{$ctx2}>
            {$r}
          </td>
EOH;
    }
    foreach( $d as $index => $data )
    {
      $ctx = NULL;
      $ctx2 = NULL;
      if( $this->use_bootstrap === true )
      {
        switch( $index )
        {
          case 0:
            $ctx2 = ' class="info text-center"';
            break;
          case 1:
            $ctx2 = ' class="success text-center"';
            break;
          case 2:
            $ctx2 = ' class="warning text-center"';
            break;
          case 3:
            $ctx2 = ' class="danger text-center"';
            break;
        }
      }
      else // $this->use_bootstrap !== true
      {
        switch( $index )
        {
          case 0:
            $ctx2 = ' style="background:rgb(217,237,247);border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
          case 1:
            $ctx2 = ' style="background:rgb(223,240,216);border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
          case 2:
            $ctx2 = ' style="background:rgb(252,248,227);border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
          case 3:
            $ctx2 = ' style="background:rgb(242,222,222);border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
        }
      }
      if( $this->headers_set === true )
      {
        $this->html .=<<<EOH
            <td{$ctx2}>
              {$data}
            </td>
EOH;
      }
      else // $this->headers_set !== true
      {
        $this->html .=<<<EOH
          <td{$ctx2}>
            {$data}
          </td>
EOH;
      }
    }
    if( $this->headers_set === true )
    {
      $this->html .=<<<EOH
          </tr>
EOH;
    }
    else // $this->headers_set !== true
    {
      $this->html .=<<<EOH
        </tr>
EOH;
    }
  }
  private function closeDataRow()
  {
    if( $this->headers_set === true )
    {
      if( $this->calc_data_set === true )
      {
        $this->html .=<<<EOH
        </tbody>
EOH;
      }
    }
    else // $this->headers_set !== true
    {
      if( $this->calc_data_set === false )
      {
        $this->html .=<<<EOH
      </tbody>
EOH;
      }
    }
  }
  private function insertCalcDataRow( $r, $d )
  {
    $ctx = ' style="background:#F5F5F5;border-top:3px double #888888;border-right:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;border-left:1px solid #DDDDDD;"';
    $ctx2 = ' style="border:1px solid #DDDDDD;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
    $cell_tag = 'td';
    if( $this->use_bootstrap === true )
    {
      $ctx = ' class="active" style="border-top:3px double #888888;"';
      $ctx2 = ' class="text-center"';
    }
    if( $r === 0 )
    {
      if( $this->headers_set === true )
      {
        $this->html .=<<<EOH
        <tfoot>
EOH;
      }
    }
    if( $this->data_set === true )
    {
      $cell_tag = 'th';
    }
    if( $this->headers_set === true )
    {
      $this->html .=<<<EOH
          <tr{$ctx}>
            <{$cell_tag}{$ctx2}>
              {$this->calc_type[ $r ]}
            </{$cell_tag}>
EOH;
    }
    else // $this->headers_set !== true
    {
      $this->html .=<<<EOH
        <tr{$ctx}>
          <{$cell_tag}{$ctx2}>
            {$this->calc_type[ $r ]}
          </{$cell_tag}>
EOH;
    }
    foreach( $d as $index => $calc_data )
    {
      $ctx = NULL;
      $ctx2 = NULL;
      if( $this->use_bootstrap === true )
      {
        switch( $index )
        {
          case 0:
            $ctx2 = ' class="text-info text-center"';
            break;
          case 1:
            $ctx2 = ' class="text-success text-center"';
            break;
          case 2:
            $ctx2 = ' class="text-warning text-center"';
            break;
          case 3:
            $ctx2 = ' class="text-danger text-center"';
            break;
        }
      }
      else // $this->use_bootstrap !== true
      {
        switch( $index )
        {
          case 0:
            // #5BC0DE
            $ctx2 = ' style="color:rgb(49,99,139);border:1px solid #DDDDDD;font-weight:bold!important;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
          case 1:
            // #5CB86C
            $ctx2 = ' style="color:rgb(60,118,61);border:1px solid #DDDDDD;font-weight:bold!important;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
          case 2:
            // #F0AD4E
            $ctx2 = ' style="color:rgb(138,109,59);border:1px solid #DDDDDD;font-weight:bold!important;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
          case 3:
            // #D9534F
            $ctx2 = ' style="color:rgb(169,68,66);border:1px solid #DDDDDD;font-weight:bold!important;text-align:center;padding:8px;vertical-align:top;line-height:1.428571429;"';
            break;
        }
      }
      if( $this->headers_set === true )
      {
        $this->html .=<<<EOH
            <{$cell_tag}{$ctx2}>
              {$calc_data}
            </{$cell_tag}>
EOH;
      }
      else // $this->headers_set !== true
      {
        $this->html .=<<<EOH
          <{$cell_tag}{$ctx2}>
            {$calc_data}
          </{$cell_tag}>
EOH;
      }
    }
    if( $this->headers_set === true )
    {
      $this->html .=<<<EOH
          </tr>
EOH;
    }
    else // $this->headers_set !== true
    {
      $this->html .=<<<EOH
        </tr>
EOH;
    }
  }
  private function closeCalcDataRow()
  {
    if( $this->headers_set === true )
    {
      if( $this->data_set === true )
      {
        $this->html .=<<<EOH
        </tfoot>
EOH;
      }
    }
    else // $this->headers_set !== true
    {
      if( $this->data_set === true )
      {
        $this->html .=<<<EOH
      </tbody>
EOH;
      }
    }
  }
  private function setupBootstrapTable()
  {
    $props = ' class="table table-hover table-bordered"';
    if( $this->title_set === true )
    {
      $props = ' id="' . $this->id . '"' . $props;
      $this->html .=<<<EOH
    <div class="container">
      <h2 class="text-center">{$this->title}</h2>
    </div>
EOH;
    }
    if( $this->is_responsive === true )
    {
      $this->html .=<<<EOH
    <div class="table-responsive">
      <table{$props}>
EOH;
    }
    else // $this->is_responsive !== true
    {
      $this->html .=<<<EOH
    <table{$props}>
EOH;
    }
  }
  private function setupBasicTable()
  {
    $props = ' style="width:100%;margin:0 auto;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;font-size:14px;border:1px solid #DDDDDD;empty-cells:show;border-collapse:collapse;line-height:1.428571429;"';
    if( $this->title_set === true )
    {
      $props = ' id="' . $this->id . '"' . $props;
      $this->html .=<<<EOH
    <div style="width:100%;">
      <h2 style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:30px;text-align:center;">{$this->title}</h2>
    </div>
EOH;
    }
    if( $this->is_responsive === true )
    {
      $this->html .=<<<EOH
    <div style="width:100%;margin:0 auto;">
      <table{$props}>
EOH;
    }
    else // $this->is_responsive !== true
    {
      $this->html .=<<<EOH
    <table{$props}>
EOH;
    }
  }
  private function finishSetup()
  {
    if( $this->is_responsive === true )
    {
      $this->html .=<<<EOH
      </table>
    </div>
EOH;
    }
    else // $this->is_responsive !== true
    {
      $this->html .=<<<EOH
    </table>
EOH;
    }
    return $this->html;
  }
}
 |