<?php
// {{{ICINGA_LICENSE_CODE}}}
// -----------------------------------------------------------------------------
// This file is part of icinga-web.
// 
// Copyright (c) 2009-2013 Icinga Developer Team.
// All rights reserved.
// 
// icinga-web 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 3 of the License, or
// (at your option) any later version.
// 
// icinga-web 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 icinga-web.  If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// {{{ICINGA_LICENSE_CODE}}}


/**
 * IcingaConfigfiles
 *
 * This class has been auto-generated by the Doctrine ORM Framework
 *
 * @package    ##PACKAGE##
 * @subpackage ##SUBPACKAGE##
 * @author     ##NAME## <##EMAIL##>
 * @version    SVN: $Id: Builder.php 7490 2010-03-29 19:53:27Z jwage $
 */
class IcingaSlahistoryTable extends Doctrine_Table {
    
    
    /**
     * @param Api_SLA_SLAFilterModel $filter
     * @param type $prefix
     * @param type $date
     * @return type 
     */
    private static function buildWherePart(Doctrine_Connection $conn,Api_SLA_SLAFilterModel $filter) {
        $queryBuilder = AgaviContext::getInstance()->getModel("SLA.SLAQueryBuilder","Api");
        
        return $queryBuilder->getWherePart($conn,$filter);
    }
    
    /**
     * Returns the SLA Summary (@see IcingaSLASummary) for this filter
     * 
     * @param Doctrine_Connection $dbConnection
     * @param type $filter
     * @return Doctrine_Collection 
     */
    public static function getSummary(Doctrine_Connection $dbConnection =null, $filter = null) {
        if($dbConnection == null)
            $dbConnection = AgaviContext::getInstance()->getDatabaseConnection("icinga");
        
        $driver = $dbConnection->getDriverName();
        $stmt = null;
        switch(strtolower($driver)) {
            case 'pgsql':
                $stmt = self::getPgsqlSummaryQuery($dbConnection, $filter);
                break;
            case 'oracle':
            case 'icingaoracle':
                $stmt = self::getOracleSummaryQuery($dbConnection,$filter);
                break;
            case 'mysql':
                $stmt = self::getMySQLSummaryQuery($dbConnection,$filter);
                break;
            default:
                throw new AppKitDoctrineException("Invalid driver ".$driver);
        }
        $stmt->execute();
        $result = new Doctrine_Collection("IcingaSLASummary");
        
        while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $record = new IcingaSLASummary();
            foreach($row as $key=>$value) {
                $record->{strtolower($key)} = $value;
            }
            $result->add($record);
        }
        
        return $result;        
    }

    private static function getTimeRangeQuery(Doctrine_Connection $c, $filter) {
        $prefix = $c->getPrefix();
        $startTime = $filter->getStartTime();
        $endTime = $filter->getEndTime();
        $DATE_FORMAT;
        $DATE;
        $NOW;
        switch(strtolower($c->getDriverName())) {
            
            case 'pgsql':
                $DATE_FORMAT = "'YYYY-MM-DD HH24:MI:SS'";
                $DATE = "TO_DATE";
                $NOW = "NOW()";
                break;
            case 'oracle':
            case 'icingaOracle':
                $DATE_FORMAT = "'YYYY-MM-DD HH24:MI:SS'";
                $DATE = "TO_DATE";
                $NOW = "CURRENT_DATE";
                break;
            case 'mysql':
                $DATE_FORMAT = "'%Y-%m-%d %H:%i:%s'";
                $DATE = "STR_TO_DATE";
                $NOW = "now()";
                break;
                
        }
        if(!$startTime && !$endTime)
            return "SELECT * FROM ".$prefix."slahistory";
        $timeRange = "SELECT state, object_id, scheduled_downtime,acknowledgement_time";
        if(!$startTime)
            $timeRange .= ",start_time";
        else 
            $timeRange .= "
                ,CASE 
                   WHEN start_time <= $DATE('$startTime',$DATE_FORMAT) AND
                        COALESCE(acknowledgement_time, end_time, $NOW) >= $DATE('$startTime',$DATE_FORMAT) THEN $DATE('$startTime',$DATE_FORMAT)
                   ELSE start_time 
                END AS start_time";

        if(!$endTime)
            $timeRange .= ",COALESCE(end_time,$NOW) as end_time";
        else 
            $timeRange .= "
                ,CASE 
                   WHEN COALESCE(acknowledgement_time, end_time, $NOW) >= $DATE('$endTime',$DATE_FORMAT) AND
                        start_time <= $DATE('$endTime',$DATE_FORMAT) THEN $DATE('$endTime',$DATE_FORMAT)
                   ELSE COALESCE(end_time,$NOW); 
                END AS end_time";
        $query = $timeRange." FROM ".$prefix."slahistory ";
        if(!($endTime || $startTime)) 
            return $query;
        $query .= "WHERE ";
        if($endTime)
            $query .= "end_time <= $DATE('$endTime',$DATE_FORMAT) ";
        if($endTime && $startTime)
            $query .= " AND ";
        if($startTime)
            $query .= "start_time >= $DATE('$startTime',$DATE_FORMAT) ";
        return $query;
        
            
    }
    
    
    private static function getPgsqlSummaryQuery(Doctrine_Connection $c, $filter = null) {
        $dbh = $c->getDbh();
        $prefix = $c->getPrefix();
        $mainQuery = "SELECT 
                (state*(scheduled_downtime-1)*-1) as sla_state, 
                s.object_id, 
                obj.objecttype_id,
                scheduled_downtime, 
                SUM(date_part('epoch',
                    COALESCE(
                        acknowledgement_time-start_time,
                        end_time-start_time,
                        NOW()-start_time
                    )
                 )) AS duration FROM timeRange s INNER JOIN ".$prefix.
                "objects obj ON obj.object_id = s.object_id ";
        
        if($filter) {
            $filterParts = self::buildWherePart($c,$filter);
        
            $mainQuery .= $filterParts["wherePart"];
        }
        $mainQuery .= " GROUP BY 
                 (state*(scheduled_downtime-1)*-1), 
                 s.object_id, 
                 obj.objecttype_id,
                 scheduled_downtime";
        
        $timeRangeQuery = self::getTimeRangeQuery($c,$filter);
        $stmt = $dbh->prepare($query = "
            WITH 
                timeRange AS (".$timeRangeQuery."),
                slatable as (".$mainQuery." ),
            completeDuration AS (
                 SELECT object_id,
                    SUM(date_part('epoch',
                        COALESCE(
                            acknowledgement_time-start_time,
                            end_time-start_time,
                            NOW()-start_time
                        ))
                    ) AS complete 
                  FROM timeRange
                  GROUP BY object_id
            ) 
            SELECT 
                s.object_id AS OBJECT_ID, 
                s.sla_state AS SLA_STATE, 
                s.objecttype_id AS OBJECTTYPE_ID,
                SUM(s.duration/c.complete*100) as PERCENTAGE
            FROM slatable s 
            INNER JOIN 
                completeDuration c 
                ON 
                    c.object_id = s.object_id          
            GROUP BY s.object_id, s.sla_state, s.objecttype_id
        ");
        foreach($filterParts["params"] as $param=>$value)
            $stmt->bindValue($param,$value);
        return $stmt;
        
    }
    
    private static function getOracleSummaryQuery(Doctrine_Connection $c, $filter = null) {    
        $dbh = $c->getDbh();
        $prefix = $c->getPrefix();
        $mainQuery = "SELECT 
                (state*(scheduled_downtime-1)*-1) as sla_state, 
                s.object_id,
                obj.objecttype_id,
                scheduled_downtime, 
                SUM(
                        COALESCE(
                            cast(acknowledgement_time as date)-cast(start_time as date),
                            cast(end_time as date)-cast(start_time as date),
                            CURRENT_DATE-cast(start_time as date)
                        )
                 )*86400 AS duration FROM timeRange s INNER JOIN ".$prefix.
                "objects obj ON obj.id = s.object_id ";
        
        if($filter) {
            $filterParts = self::buildWherePart($c,$filter);
            $mainQuery .= $filterParts["wherePart"];
        }
        $mainQuery .= " GROUP BY 
                 (state*(scheduled_downtime-1)*-1), 
                 s.object_id, 
                 obj.objecttype_id,
                 scheduled_downtime";
        
        $timeRangeQuery = self::getTimeRangeQuery($c,$filter);
        $stmt = $dbh->prepareBase($query = "WITH 
                timeRange AS (".$timeRangeQuery."),
                slatable as (".$mainQuery." ),
            completeDuration AS (
                 SELECT object_id,
                    SUM(
                        COALESCE(
                            cast(acknowledgement_time as date)-cast(start_time as date),
                            cast(end_time as date)-cast(start_time as date),
                            CURRENT_DATE-cast(start_time as date)
                        )
                    )*86400 AS complete 
                  FROM timeRange
                  GROUP BY object_id
            ) 
            SELECT 
                s.object_id AS OBJECT_ID, 
                s.sla_state AS SLA_STATE,
                s.objecttype_id AS OBJECTTYPE_ID,
                SUM(s.duration/c.complete*100) as PERCENTAGE
            FROM slatable s 
            INNER JOIN 
                completeDuration c 
                ON 
                    c.object_id = s.object_id          
            GROUP BY s.object_id, s.sla_state, s.objecttype_id
        ");
      
        
        foreach($filterParts["params"] as $param=>$value)
            $stmt->bindValue($param,$value);
        
        return $stmt;
    }
    
    private static function getMySQLSummaryQuery(Doctrine_Connection $c, $filter = null) {   
        $dbh = $c->getDbh();
        $prefix = $c->getPrefix();
        $timeQuery = self::getTimeRangeQuery($c,$filter);

        // MYSQL has no with clause, so we need two queries
        $mainQuery = "(SELECT 
                s.object_id,
                state*(scheduled_downtime-1)*-1 as sla_state,
                obj.objecttype_id,
                SUM(
                    COALESCE(
                        UNIX_TIMESTAMP(acknowledgement_time)-UNIX_TIMESTAMP(start_time),
                        UNIX_TIMESTAMP(end_time)-UNIX_TIMESTAMP(start_time),
                        UNIX_TIMESTAMP(now())-UNIX_TIMESTAMP(start_time)
                    )
                ) as duration          
             FROM  ($timeQuery) s
             INNER JOIN ".$prefix."objects obj ON obj.object_id = s.object_id ";
        
        if($filter) {
            $filterParts = self::buildWherePart($c,$filter);
            $mainQuery .= $filterParts["wherePart"];
        }
        
        $mainQuery .= "            
             GROUP BY 
                 state*(scheduled_downtime-1)*-1,
                 object_id,
                 objecttype_id
             ) slahistory_main";
         
       
        $stmt = $dbh->prepare($query = "
            
            SELECT 
                slahistory_main.sla_state AS SLA_STATE, 
                slahistory_main.object_id AS OBJECT_ID, 
                slahistory_main.objecttype_id AS OBJECTTYPE_ID,
                SUM(slahistory_main.duration/s.complete*100) AS PERCENTAGE
            FROM
                 $mainQuery 
                 INNER JOIN (
                     SELECT t1.object_id,
                     SUM(
                         COALESCE(
                             UNIX_TIMESTAMP(acknowledgement_time)-UNIX_TIMESTAMP(start_time),
                             UNIX_TIMESTAMP(end_time)-UNIX_TIMESTAMP(start_time),
                             UNIX_TIMESTAMP(now())-UNIX_TIMESTAMP(start_time)
                         )         
                    ) as complete FROM ($timeQuery) t1
                    GROUP BY 
                        object_id     
                 ) as s ON slahistory_main.object_id = s.object_id  
             GROUP BY 
                slahistory_main.object_id,
                slahistory_main.sla_state,
                slahistory_main.objecttype_id;
         ");
       
        foreach($filterParts["params"] as $param=>$value)
            $stmt->bindValue($param,$value);

        return $stmt;
       
    }
}