if ( typeof( IPG ) == 'undefined' ) IPG = {};
IPG.ServiceListManager = function( container , config ){
    this.version = "0.1";
    
    this.container = container;
    this.document = container.document;
    
    this.config = config;
    if( !this.config ) return;
    this.chHeaderImgPath = this.config.config_xml.img_path.epg_ch_body;
    
    this.chTimelineTopPath = this.config.config_xml.img_path.epg_ch_timeline_top;
    this.chTimelineRepPath = this.config.config_xml.img_path.epg_ch_timeline_rep;
    this.chTimelineBottomPath = this.config.config_xml.img_path.epg_ch_timeline_bottom;
    this.pgTimelineTopPath1 = this.config.config_xml.img_path.epg_pg_timeline_top1;
    this.pgTimelineRepPath1 = this.config.config_xml.img_path.epg_pg_timeline_rep1;
    this.pgTimelineBottomPath1 = this.config.config_xml.img_path.epg_pg_timeline_bottom1;
    this.pgTimelineTopPath2 = this.config.config_xml.img_path.epg_pg_timeline_top2;
    this.pgTimelineRepPath2 = this.config.config_xml.img_path.epg_pg_timeline_rep2;
    this.pgTimelineBottomPath2 = this.config.config_xml.img_path.epg_pg_timeline_bottom2;
    this.pgTimelineTopPath3 = this.config.config_xml.img_path.epg_pg_timeline_top3;
    this.pgTimelineRepPath3 = this.config.config_xml.img_path.epg_pg_timeline_rep3;
    this.pgTimelineBottomPath3 = this.config.config_xml.img_path.epg_pg_timeline_bottom3;
    
    this.station_width = this.config.config_xml.epg_info.station_width;
    this.timeline_width = this.config.config_xml.epg_info.timeline_width;
    this.resize_flg = this.config.resize_flg;
    this.minute_height = this.config.config_xml.epg_info.minute_height;
    this.zoom_rate = this.config.config_xml.epg_info.zoom_rate;
    this.default_color = this.config.config_xml.color_info.color_default;
    this.color_palette = this.config.config_xml.color_info.color_palette;
    
    // パース用のキー達
    this.key_name = "name";
    this.key_network_id = "network_id";
    this.key_url = "url";
    this.key_remocon_key = "remote_controller_key";
    this.key_main_ch = "main_ch";
    this.key_logoimage_l = "logo_image_large";
    this.key_logoimage_m = "logo_image_middle";
    this.key_ch = "ch";
    this.key_serviceid = "service_id";
    this.key_type = "type";
    this.key_threedigit = "three_digit";
    
    return this;
};

IPG.ServiceListManager.prototype.getServiceList = function(){
    this.servicelist = new Array();
    this.genre_color = this.config.cookie.genrecolor;
    var ajaxOpt = {
        'method': 'get',
        'asynchronous': false
    };
    var url = "";
    if( this.config.cookie.bctype == "BSD" ) {
        url = this.config.config_xml.api_url.getServiceList + "/type_"+this.config.cookie.bctype + "/area_"+this.config.cookie.area + "/sorttype_1";
    }else{
        url = this.config.config_xml.api_url.getServiceList + "/type_"+this.config.cookie.bctype + "/area_"+this.config.cookie.area + "/sorttype_"+this.config.cookie.sorttype;
    }
//IPG.Utility.debugOut( '[getServiceList['+url+']' , "debug" , "teal" );
    if( this.container.isLocal ) url = this.config.config_xml.api_url.getServiceList;
//IPG.Utility.debugOut( '[getServiceList['+url+']' , "debug" , "teal" );
    var xhrObj = new Ajax.Request( url , ajaxOpt );
    if( xhrObj && xhrObj._complete ){
        
        // HTMLを生成する前に、今の構成をクリアする。
        // ServiceListのイベントリムーブ処理（あれば）
        // ProgramListのイベントリムーブ処理。
        // HTMLのクリア。
        this.loadcounter = {};
        this.earliestPgTime = null;
        this.latestPgTime = null;
        
        // HTML生成前に、現在のHTMLを削除。
        var header = $( "epg_header" );
        if( header.childNodes && header.childNodes.length ){
            while( header.firstChild ) header.removeChild( header.firstChild );
        }
        var body = $( "epg_body" );
        if( body.childNodes && body.childNodes.length ){
            while( body.firstChild ) body.removeChild( body.firstChild );
        }
        body.style.width = 0;
        body.style.height = 0;
        
        this.parseServiceListData( xhrObj.transport.responseXML.documentElement );
    }else{
        Element.setStyle( $( "epg_cloak" ) , "display: block;" );
        $( "cloak_img" ).src = this.config.error_image;
    }
};
IPG.ServiceListManager.prototype.parseServiceListData = function( xml_data ){
    if( !xml_data ) return;
    
    var stationDataList = xml_data.childNodes;
    if( stationDataList && stationDataList.length ){
        var list_length = stationDataList.length;
        
        var headerHTML = "";
        var timeline_count = 0;
        var timeline_count_base = 2;
        var timeline_count_now = timeline_count_base;
        for( var i = 0; i < list_length; i++ ){
            --timeline_count_now;
            var stationData = stationDataList[i];
            var station = {};
            station.name = stationData.getElementsByTagName(  this.key_name )[0].firstChild.nodeValue;
            station.network_id = stationData.getElementsByTagName(  this.key_network_id )[0].firstChild.nodeValue;
            station.url = stationData.getElementsByTagName(  this.key_url )[0].firstChild.nodeValue;
            station.remote_controller_key = stationData.getElementsByTagName(  this.key_remocon_key )[0].firstChild.nodeValue;
            station.main_ch = stationData.getElementsByTagName(  this.key_main_ch )[0].firstChild.nodeValue;
            station.logo_image_large = stationData.getElementsByTagName(  this.key_logoimage_l )[0].firstChild.nodeValue;
            station.logo_image_middle = stationData.getElementsByTagName(  this.key_logoimage_m )[0].firstChild.nodeValue;
            var chlist = stationData.getElementsByTagName(  this.key_ch )[0].childNodes;
            if( chlist && chlist.length){
                station.ch = [];
                for( var j = 0 , ch_length = chlist.length ; j < ch_length; j++ ){
                    var chData = chlist[j];
                    var ch = {};
                    ch.service_id = chData.getElementsByTagName(  this.key_serviceid )[0].firstChild.nodeValue;
                    ch.type = chData.getElementsByTagName(  this.key_type )[0].firstChild.nodeValue;
                    ch.three_digit = chData.getElementsByTagName(  this.key_threedigit )[0].firstChild.nodeValue;
                    if( ch.service_id == station.main_ch ) station.main_ch_three_digit = ch.three_digit;
                    station.ch[j] = ch;
                }
            }
            headerHTML += this.makeStationHTML( station , i , timeline_count );
            if( !timeline_count_now ){
                headerHTML += this.makeTimeLineHTML( i , timeline_count );
                ++timeline_count;
                timeline_count_base = ( timeline_count_base == 2 ) ? 3 : 2;
                timeline_count_now = timeline_count_base;
            }
            this.servicelist.push( station );
        }
        
        this.setContentWidth( list_length , timeline_count );
        
        // 生成したヘッダ部の埋め込み。
        $( "epg_header" ).innerHTML = headerHTML;
        
        this.getProgramList();
    }
};

IPG.ServiceListManager.prototype.setContentWidth = function( station_count , timeline_count ){
    // HTML生成。コンテンツ幅
    var content_width = this.station_width*station_count + this.timeline_width*timeline_count;
    $( "epg_body" ).style.width = content_width+"px";
    $( "epg_header" ).style.width = content_width+"px";
};

IPG.ServiceListManager.prototype.makeTimeLineHTML = function( station_count , timeline_count ){
    
    var offsetLeft = ( station_count * this.station_width ) + ( timeline_count * this.timeline_width );
    
    // BODY部のタイムライン枠のみ生成
    var epgBodyTimeLineNode = this.document.createElement("div");
    $( "epg_body" ).appendChild( epgBodyTimeLineNode );
    epgBodyTimeLineNode.setAttribute( "name" , "timeline_body");
    var timelineStyle = epgBodyTimeLineNode.style;
    timelineStyle.width =  this.timeline_width+"px";
    timelineStyle.position = "absolute";
    timelineStyle.top = "0px";
    timelineStyle.left = (offsetLeft+this.station_width)+"px";
    timelineStyle[(timelineStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat')] = "left";
    
    var html = "<div name=\"timeline_header\" style=\"width: 20px; height: 53px; position: absolute; left: "+(offsetLeft+this.station_width)+"px; float: left;\">";
    html += "<div style=\"height: 1px;\"><img src=\""+this.chTimelineTopPath+"\"></div>";
    html += "<div style=\"height: 51px; background-image: url("+this.chTimelineRepPath+");\"></div>";
    html += "<div style=\"height: 1px;\"><img src=\""+this.chTimelineBottomPath+"\"></div>";
    html += "</div>";
    return html;
};

IPG.ServiceListManager.prototype.makeStationHTML = function( station_node , station_count , timeline_count ){
    
    // HTML生成 BODY部枠のみ
    var epgBodyNode = this.document.createElement("div");
    $( "epg_body" ).appendChild( epgBodyNode );
    epgBodyNode.id = "ch_body"+station_node.main_ch;
    var bodyStyle = epgBodyNode.style;
    bodyStyle.width = this.station_width+"px";
    bodyStyle.height = "1px";
    bodyStyle.position = "absolute";
    bodyStyle.top = "0px";
    var offsetLeft = ( station_count * this.station_width ) + ( timeline_count * this.timeline_width );
    bodyStyle.left = offsetLeft+"px";
    bodyStyle[(bodyStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat')] = "left";
    
    // HTML生成。ヘッダ部
    var html = "";
    html += "<div id=\"ch_header"+station_node.main_ch+"\" style=\"background-image: url( "+this.chHeaderImgPath+" ); position: absolute; left: "+offsetLeft+"px; float: left;\">";
    html += "<table border=0 cellpadding=0 cellspacing=0 width=\"120\" height=\"53\">";
    html += "<tr valign=middle height=\"34\">";
    html += "<td width=\"30\" style=\"margin: 1px 0px 0px 1px; padding-left: 4px;\"><img src=\""+station_node.logo_image_middle+"\" style=\"padding: 2px;\"></td>";


    var fs=this.container.fontSize;

    html += "<td width=\"80\" style=\"font-weight: bold; font-size: "+fs+"; margin: 1px 1px 0px 0px; padding-left: 4px; padding-right: 2px;\">"+station_node.name+"</td>";
    html += "</tr>";
    html += "<tr align=center valign=middle height=\"14\">";
    html += "<td width=\"120\" colspan=2 style=\"font-size: "+fs+"; margin: 0px 1px 0px 1px;\">"+station_node.main_ch_three_digit+"</td>";
    html += "</tr>";
    html += "<tr width=\"120\" height=\"5\"><td colspan=2></td></tr>";
    html += "</table>";
    html += "</div>";
    return html;
};

IPG.ServiceListManager.prototype.getProgramList = function(){
    if( !this.servicelist || !this.servicelist.length ) return;
    var servicelist_length = this.servicelist.length;
    if( !this.loadcounter.station_count ) this.loadcounter.station_count = servicelist_length;
    for( var i = 0; i < servicelist_length; i++ ){
        var station = this.servicelist[i];
        var ajaxOpt = {
            'method': 'get',
            'asynchronous': true,
            'onSuccess': this.onProgramListSuccess.bindAsEventListener( this , station ),
            'onFailure': this.onProgramListFailure.bind( this )
        };
        var url = station.url + "/date_"+this.config.current_date;
        if( this.container.isLocal ) url = station.url;
//IPG.Utility.debugOut( '[getProgramList['+url+']' , "debug" , "forestgreen" );
        new Ajax.Request( url , ajaxOpt );
    }
};

IPG.ServiceListManager.prototype.onProgramListSuccess = function( xhrObj , station ){
    if( xhrObj && xhrObj.responseXML && xhrObj.responseXML.documentElement ){
        xml_data = xhrObj.responseXML.documentElement;
        station.epg_version = xml_data.getElementsByTagName("epg_version")[0].firstChild.nodeValue;
        station.epg_date = xml_data.getElementsByTagName("epg_date")[0].firstChild.nodeValue;
        
        var df = this.document.createDocumentFragment();
        
        var channelDataList = xml_data.getElementsByTagName("channels")[0];
        if( channelDataList ){
            if( channelDataList.childNodes && channelDataList.childNodes.length ){
                for( var i = 0 , chdatalist_length = channelDataList.childNodes.length; i < chdatalist_length; i++ ){
                    var channelData = channelDataList.childNodes[i];
                    var service_id = channelData.getElementsByTagName("service_id")[0].firstChild.nodeValue;
                    var channel = this.getChannel( station , service_id );
                    if( !channel ) continue;
                    
                    var programList = [];
                    var programDataList = channelData.getElementsByTagName("program_list")[0].childNodes;
                    for( var j = 0 , programlist_length = programDataList.length; j < programlist_length; j++ ){
                        var program = {};
                        var programData = programDataList[j];
                        program.event_id = programData.getElementsByTagName("event_id")[0].firstChild.nodeValue;
                        
                        var title = programData.getElementsByTagName("title")[0].firstChild;
                        program.title = ( title ) ? title.nodeValue : undefined;
                        var synopsis = programData.getElementsByTagName("synopsis")[0].firstChild;
                        program.synopsis = ( synopsis ) ? synopsis.nodeValue : undefined;
                        var major_genre = programData.getElementsByTagName("major_genre")[0].firstChild;
                        program.major_genre = ( major_genre ) ? major_genre.nodeValue : undefined;
                        var minor_genre = programData.getElementsByTagName("minor_genre")[0].firstChild;
                        program.minor_genre = ( minor_genre ) ? minor_genre.nodeValue : undefined;
                        program.start_date_time = programData.getElementsByTagName("start_date_time")[0].firstChild.nodeValue;
                        program.end_date_time = programData.getElementsByTagName("end_date_time")[0].firstChild.nodeValue;
                        program.program_detail_url = programData.getElementsByTagName("program_detail_url")[0].firstChild.nodeValue;
                        programList[j] = program;
                        
                        if( service_id == station.main_ch ){
                            
                            if( !j ){
                                var firstNode = this.document.createElement('div');
                                $( "ch_body"+station.main_ch ).appendChild( firstNode );
                                firstNode.id = "pg_frame_"+station.main_ch+"_top";
                                firstNode.style.position = "absolute";
                                firstNode.style.width = (((this.station_width-1) > 0 ) ? (this.station_width-1) : 0)+"px";
                                firstNode.appendChild( this.document.createElement('div') );
                            }
                            
                            /** 過去番組が表示出来るようになったらこの部分いらないな **/
                            var pgStartDateTime = program.start_date_time;
                            var checkToday = false;
                            var today_str = $( "epg_date_controll_0" ).getAttribute( "value" );
                            if( this.config.current_date == today_str ){
                                // 当日アクセスの場合、アクセス時間と番組の開始時間とを比較し、
                                // 開始時間がアクセス時間よりも過去の場合、当該番組の開始時間をアクセス時間とみなし、
                                // 番組の高さを決定する。
                                if( IPG.Utility.comparSIDateStr( this.config.server_date.time , program.start_date_time ) < 0 ){
                                    // 番組開始時間がアクセス時間よりも過去。
                                    if( IPG.Utility.comparSIDateStr( this.config.server_date.time , program.end_date_time ) < 0 ){
                                        // 番組終了時間もアクセス時間より過去。→当該番組は表示しない
                                        continue;
                                    }else{
                                        pgStartDateTime = IPG.Utility.getSIDateFullStrFromMillisec( this.config.server_date.time );
                                    }
                                }else{
                                    // 番組開始時間がアクセス時間と等しいか、未来の場合、番組枠の高さに制限は設けない
                                }
                                checkToday = true;
                            }else{
                                // 当日ではないので、枠の制御は行わない。
                            }
                            /** 過去番組が表示出来るようになったらこの部分いらないな **/
                            
                            var totalTime = IPG.Utility.getMinuteDistance( pgStartDateTime , program.end_date_time );
                            var pgHeight = ( this.resize_flg ) ? ( totalTime * this.minute_height * this.zoom_rate ) : ( totalTime * this.minute_height );
                            
                            // 全局、全番組中の最も早く始まる番組の開始時間を取得。
                            this.checkEarliestPgTime( pgStartDateTime , checkToday );
                            
                            // 全局、全番組中の最も遅く終わる番組の終了時間を取得。
                            this.checkLatestPgTime( program.end_date_time );
                            
                            // カラーオブジェクトを取得
                            var colorObj = this.default_color;
                            if( program.major_genre && this.genre_color ){
                                var major_genre = parseInt(program.major_genre,10);
                                if( major_genre < this.config.config_xml.epg_info.startReservedGenreId ){
                                    colorObj = this.color_palette[ this.genre_color[major_genre] ];
                                }
                            }
                            
                            var frameElm = this.document.createElement('div');
                            frameElm.id = "pg_frame_"+station.main_ch+"_"+j;
                            var frameStyle = frameElm.style;
                            Element.setStyle( frameElm , "position: absolute; overflow: hidden; padding: 2px 5px 0px 5px;" );
                            frameStyle.backgroundColor = "#"+colorObj.bg.substring( 2 , 8 );

                            //frameStyle.width =  (((this.station_width-1-5-5) > 0 ) ? (this.station_width-1-5-5) : 0)+"px";
                            //frameStyle.height = (((pgHeight-1-2) > 0 ) ? (pgHeight-1-2) : 0)+"px";

                            frameStyle.fontSize = this.container.fontSize;

			var ww=this.station_width;
			var hh=pgHeight;

			if (typeof document.body.style.maxHeight != "undefined" 
			// ||	this.container.isFullEPG
			){
				ww=ww-1-5-5;
				hh=hh-1-2;
			}
                            frameStyle.width =  (((ww) > 0 ) ? (ww) : 0)+"px";
                            frameStyle.height = (((hh) > 0 ) ? (hh) : 0)+"px";



                            frameStyle.borderRight = "1px solid rgb( 156 , 156 , 156 )";
                            frameStyle.borderBottom = "1px solid rgb( 156 , 156 , 156 )";
                            df.appendChild( frameElm );
                            frameElm.setAttribute( "genre" , program.major_genre );
                            
                            var pgContent = IPG.Utility.getHHMMFromSIDateStr( program.start_date_time )+" "+((program.title)?program.title:"");
                            var titleSpan = this.document.createElement('span');
                            frameElm.appendChild( titleSpan );
                            titleSpan.setAttribute( "name" , "title" );
                            titleSpan.style.color = "#"+colorObj.cap.substring( 2 , 8 );
                            titleSpan.appendChild( this.document.createTextNode( pgContent ) );
                            
                            // TODO
                            // [synopsis]の表示制限。
                            // 番組タイトル行が何行になるかを計算し、番組の表示領域に合わせて[synopsis]を生成する。
                            // 拡大表示時の高さを基準として、番組枠の高さを求め、
                            // タイトルが占める表示領域を除いたあまりを求める。
                            // 求められた領域に対して、表示可能な[synopsis]の文字数を求め、それを表示する。
                            // 放送時間によっては、番組タイトル自体に制限をかけ、[synopsis]は全く表示しない等もアリ。
                            
                            if( program.synopsis != undefined && this.resize_flg ){
                                frameElm.appendChild( this.document.createElement( "br" ) );
                                var synopsisSpan = this.document.createElement('span');
                                frameElm.appendChild( synopsisSpan );
                                synopsisSpan.setAttribute( "name" , "synopsis" );
                                synopsisSpan.style.color = "#"+colorObj.text.substring( 2 , 8 );
                                synopsisSpan.appendChild( this.document.createTextNode( program.synopsis ) );
                            }
                            frameElm.appendChild( this.document.createElement('div') );
                        }
                    }
                    
                    if( service_id == station.main_ch ){
                        $( "ch_body"+station.main_ch ).appendChild( df );
                        var lastNode = this.document.createElement('div');
                        $( "ch_body"+station.main_ch ).appendChild( lastNode );
                        lastNode.id = "pg_frame_"+station.main_ch+"_last";
                        lastNode.style.position = "absolute";
                        lastNode.style.width = (((this.station_width-1) > 0 ) ? (this.station_width-1) : 0)+"px";
                        lastNode.style.borderRight = "1px solid rgb( 156 , 156 , 156 )";
                        lastNode.style.borderBottom = "1px solid rgb( 156 , 156 , 156 )";
                        lastNode.appendChild( this.document.createElement('div') );
                    }
                    channel.programList = programList;
                }
                
                // ロード完了フラグを立てる。
               if( !this.loadcounter[station.network_id] ) this.loadcounter[station.network_id] = true;
                
            }else{
                // レスポンスは取得したものの、番組情報がない場合。
                var firstNode = this.document.createElement('div');
                $( "ch_body"+station.main_ch ).appendChild( firstNode );
                firstNode.id = "pg_frame_"+station.main_ch+"_top";
                firstNode.style.position = "absolute";
                firstNode.style.width = (((this.station_width-1) > 0 ) ? (this.station_width-1) : 0)+"px";
                firstNode.appendChild( this.document.createElement('div') );
                
                var lastNode = this.document.createElement('div');
                $( "ch_body"+station.main_ch ).appendChild( lastNode );
                lastNode.id = "pg_frame_"+station.main_ch+"_last";
                lastNode.style.position = "absolute";
                lastNode.style.width = (((this.station_width-1) > 0 ) ? (this.station_width-1) : 0)+"px";
                lastNode.style.borderRight = "1px solid rgb( 156 , 156 , 156 )";
                lastNode.style.borderBottom = "1px solid rgb( 156 , 156 , 156 )";
                lastNode.appendChild( this.document.createElement('div') );
                
                // ロード未完了フラグを立てる。
               if( !this.loadcounter[station.network_id] ) this.loadcounter[station.network_id] = "no_data";
            }
        }
        
        // 指定地域の全局分の情報取得が出来たか？
        var loadcount = 0;
        var nodata_count = 0;
        for( key in this.loadcounter ){
            if( key == "station_count" ) continue;
            if( key == "error" ){
                Element.setStyle( $( "epg_cloak" ) , "display: block;" );
                $( "cloak_img" ).src = this.config.error_image;
                return false;
            }else if( this.loadcounter[key] == "no_data" ){
                nodata_count++;
            }
            loadcount++;
        }
        if( nodata_count == loadcount ){
            Element.setStyle( $( "epg_cloak" ) , "display: block;" );
            $( "cloak_img" ).src = this.config.error_image;
            return false;
        }
        if( loadcount == this.loadcounter.station_count ){
            // 全局分の情報ロードが終了した。
            //IPG.Utility.debugOut( '[ALL DATA LOAD COMPLETE !!!]['+loadcount+']['+this.loadcounter.station_count+']' , "debug" , "forestgreen" );
            
            this.correctHTML();
            
            if( !this.container.programLoadComplete() ) return false;
            
            Element.setStyle( $( "epg_cloak" ) , "display: none;" );
        }
    }
};
IPG.ServiceListManager.prototype.onProgramListFailure = function( xhrObj ){
    if( !this.loadcounter["error"] ) this.loadcounter["error"] = true;
    //IPG.Utility.debugOut( '[onProgramListFailure]' , "debug" , "forestgreen" );
};
IPG.ServiceListManager.prototype.correctHTML = function(){
    
    // コンテンツノードに高さを設定
    var bodyFrameHeight = IPG.Utility.trimUnit( $( "epg_body_frame" ).style.height );
    var totalTime = IPG.Utility.getMinuteDistance( this.earliestPgTime , this.latestPgTime );
    var totalBodyHeight = ( this.resize_flg ) ? ( totalTime * this.minute_height * this.zoom_rate ) : ( totalTime * this.minute_height );
    $( "epg_body" ).style.height = totalBodyHeight+"px";
    var bodyChildren = $( "epg_body" ).childNodes;
    for( var i = 0 , children_length = bodyChildren.length; i < children_length; i++ ){
        var child = bodyChildren[i];
        if( child.nodeType != 1 ) continue; // 保険もしくはIE対策。Elementじゃないノードはremoveでもいいかも？
        if( child.getAttribute( "name" ) == "timeline_body" ){
            totalBodyHeight = ( bodyFrameHeight <= totalBodyHeight ) ? totalBodyHeight : bodyFrameHeight;
            child.style.height = totalBodyHeight+"px";
        }
    }
    var fs=this.container.fontSize;
    
    
    var earliestTime = this.earliestPgTime;
    var latestTime = this.latestPgTime;
    var checkHour = function( hour ){
        if( typeof( hour ) != "number" ) return 0;
        if( 5 <= hour && hour < 11 ) return 1;
        else if( 11 <= hour && hour < 19 ) return 2;
        else if( 19 <= hour && hour < 23 ) return 1;
        else return 3;
    };
    var tl_bg_top_path = undefined;
    var tl_bg_rep_path = undefined;
    var tl_bg_btm_path = undefined;
    var setPath = function( hour_type ){
        if( hour_type == 1 ){
            tl_bg_top_path = this.pgTimelineTopPath1;
            tl_bg_rep_path = this.pgTimelineRepPath1;
            tl_bg_btm_path = this.pgTimelineBottomPath1;
        }else if( hour_type == 2 ){
            tl_bg_top_path = this.pgTimelineTopPath2;
            tl_bg_rep_path = this.pgTimelineRepPath2;
            tl_bg_btm_path = this.pgTimelineBottomPath2;
        }else if( hour_type == 3 ){
            tl_bg_top_path = this.pgTimelineTopPath3;
            tl_bg_rep_path = this.pgTimelineRepPath3;
            tl_bg_btm_path = this.pgTimelineBottomPath3;
        }
    }.bind( this );
    
    // 時間枠に時間を設定
    var firstHour = IPG.Utility.getHourFromSIDateStr( earliestTime );
    setPath( checkHour( firstHour ) );
    var distanceNextHour = IPG.Utility.getMinuteToNextHour( earliestTime );
    var firstHourHieght = ( this.resize_flg ) ? ( distanceNextHour * this.minute_height * this.zoom_rate ) : ( distanceNextHour * this.minute_height );
    var html = "<div style=\"position: relative; height:"+firstHourHieght+"px; overflow: hidden;\">";
    html += "<div style=\"height: 1px;\"><img src=\""+tl_bg_top_path+"\" style=\"\"></div>";

    html += "<div style=\"height: "+(firstHourHieght-2)+"px; background-image: url("+tl_bg_rep_path+");\"><span style=\"font-size: "+fs+"; position: absolute; top: 50%; left: 50%; margin-top: -0.5em; margin-left: -0.5em;\">"+( ( firstHour < 10 ) ? ( "0"+firstHour ) : firstHour )+"</span></div>";
    html += "<div style=\"height: 1px;\"><img src=\""+tl_bg_btm_path+"\" style=\"\"></div>";
    html += "</div>";

    var drawHeight = firstHourHieght;
    var hourHeight = ( this.resize_flg ) ? ( 60 * this.minute_height * this.zoom_rate ) : ( 60 * this.minute_height );
    while( drawHeight < totalBodyHeight ){
        ++firstHour;
        if( firstHour > 23 ) firstHour = 0;
        setPath( checkHour( firstHour ) );
        drawHeight += hourHeight;
        if( drawHeight > totalBodyHeight ) hourHeight -= ( drawHeight - totalBodyHeight );
        html += "<div style=\"position: relative; height:"+hourHeight+"px; overflow: hidden;\">";
        html += "<div style=\"height: 1px;\"><img src=\""+tl_bg_top_path+"\" style=\"\"></div>";
        html += "<div style=\"height: "+(hourHeight-2)+"px; background-image: url("+tl_bg_rep_path+");\"><span style=\"font-size: "+fs+"; position: absolute; top: 50%; left: 50%; margin-top: -0.5em; margin-left: -0.5em;\">"+( ( firstHour < 10 ) ? ( "0"+firstHour ) : firstHour )+"</span></div><div></div>";
        html += "<div style=\"height: 1px;\"><img src=\""+tl_bg_btm_path+"\" style=\"\"></div>";
        html += "</div>";
    }
    var bodyElement = $( "epg_body" );
    if( bodyElement && bodyElement.childNodes ){
        for( var i = 0 , len = bodyElement.childNodes.length; i < len; i++ ){
            var child = bodyElement.childNodes[i];
            if( child.getAttribute( "name" ) == "timeline_body" ){
                child.innerHTML = html;
            }
        }
    }
    
    // 番組枠の位置補正
    for( var i = 0 , servicelist_length = this.servicelist.length; i < servicelist_length; i++ ){
        var main_ch = this.servicelist[i].main_ch;
        var programDataList = this.getMainChannel( this.servicelist[i] , main_ch ).programList;
        var newTop = undefined;
        
        var correctHeight = undefined;
        if( programDataList ){
            for( var j = 0 , length = programDataList.length; j < length; j++ ){
                var targetElement = $( "pg_frame_"+main_ch+"_"+j );
                if( targetElement && targetElement.style ){
                    correctHeight = 0;
                    var pgStartTime = programDataList[j].start_date_time;
                    if( IPG.Utility.comparSIDateStr( earliestTime , pgStartTime ) > 0 ){
                        var diff = IPG.Utility.getMinuteDistance( earliestTime , pgStartTime );
                        correctHeight = ( this.resize_flg ) ? ( diff * this.minute_height * this.zoom_rate ) : ( diff * this.minute_height );
                        targetElement.style.top = correctHeight+"px";
                        if( !j ){
                            var firstNode = $( "pg_frame_"+main_ch+"_top" );
                            firstNode.style.height = (correctHeight-1)+"px";
                            firstNode.style.borderRight = "1px solid rgb( 156 , 156 , 156 )";
                            firstNode.style.borderBottom = "1px solid rgb( 156 , 156 , 156 )";
                        }
                    }
                    if( (j+1) == length ){
                        var pgEndTime = programDataList[j].end_date_time;
                        if( IPG.Utility.comparSIDateStr( latestTime , pgEndTime ) < 0 ){
                            var lastNode = $( "pg_frame_"+main_ch+"_last" );
                            var nodeTop = correctHeight + IPG.Utility.trimUnit( targetElement.style.height );
                            lastNode.style.top = (nodeTop+2+1)+"px";
                            var diff = IPG.Utility.getMinuteDistance( pgEndTime , latestTime );
                            var nodeHeight = ( this.resize_flg ) ? ( diff * this.minute_height * this.zoom_rate ) : ( diff * this.minute_height );
                            lastNode.style.height = (nodeHeight-1)+"px";
                            lastNode.style.borderRight = "1px solid rgb( 156 , 156 , 156 )";
                            lastNode.style.borderBottom = "1px solid rgb( 156 , 156 , 156 )";
                        }
                    }
                }
            }
        }
            if( correctHeight == undefined ){
                var lastNode = $( "pg_frame_"+main_ch+"_last" );
                lastNode.style.top = "0px";
                var diff = IPG.Utility.getMinuteDistance( earliestTime , latestTime );
                var nodeHeight = ( this.resize_flg ) ? ( diff * this.minute_height * this.zoom_rate ) : ( diff * this.minute_height );
                lastNode.style.height = (nodeHeight-1)+"px";
                lastNode.style.borderRight = "1px solid rgb( 156 , 156 , 156 )";
                lastNode.style.borderBottom = "1px solid rgb( 156 , 156 , 156 )";
            }
    }
};

IPG.ServiceListManager.prototype.getChannel = function( station , service_id ){
    for( var i = 0 , length = station.ch.length; i < length; i++ ){
        var channel = station.ch[i];
        if( channel.service_id == service_id ){
            return channel;
        }
    }
    return undefined;
};
IPG.ServiceListManager.prototype.getMainChannel = function( station , main_ch ){
    for( var i = 0 , length = station.ch.length; i < length; i++ ){
        var channel = station.ch[i];
        if( channel.service_id == main_ch ){
            return channel;
        }
    }
    return undefined;
};

IPG.ServiceListManager.prototype.checkEarliestPgTime = function( pg_start_time , checkToday ){
    if( !this.earliestPgTime ){
        this.earliestPgTime = pg_start_time;
    }else{
        var tmp_time_a = IPG.Utility.getTimeFromSIDateStr( this.earliestPgTime );
        var tmp_time_b = IPG.Utility.getTimeFromSIDateStr( pg_start_time );
        if( tmp_time_a > tmp_time_b ) this.earliestPgTime = pg_start_time
    }
    // 開始時間のみ、さらにサーバタイムと比較。
    if( checkToday && IPG.Utility.getTimeFromSIDateStr( this.earliestPgTime ) < this.config.server_date.time ){
        this.earliestPgTime = IPG.Utility.getSIDateFullStrFromMillisec( this.config.server_date.time );
    }
};
IPG.ServiceListManager.prototype.checkLatestPgTime = function( pg_end_time ){
    if( !this.latestPgTime ){
        this.latestPgTime = pg_end_time;
    }else{
        var tmp_time_a = IPG.Utility.getTimeFromSIDateStr( this.latestPgTime );
        var tmp_time_b = IPG.Utility.getTimeFromSIDateStr( pg_end_time );
        if( tmp_time_a < tmp_time_b ) this.latestPgTime = pg_end_time
    }
};

IPG.ServiceListManager.prototype.getProgramDetail = function( main_ch , pgCount ){
    if( main_ch == undefined || pgCount == undefined ) return;
    if( this.servicelist == undefined ) return;
    var obj = undefined;
    
    for( var i = 0 , servicelist_length = this.servicelist.length; i < servicelist_length; i++ ){
        if( main_ch == this.servicelist[i].main_ch ){
            obj = {};
            var station = this.servicelist[i];
            if( !station ) return obj;
            var programData = this.getMainChannel( station , main_ch ).programList[pgCount];
            if( !programData ) return obj;
            // バルーンないし、ポップアップで表示する内容だけ
            obj.station_name = station.name;
            obj.three_digit = station.main_ch_three_digit;
            obj.remote_controller_key = station.remote_controller_key;
            obj.logo_image = station.logo_image_middle;
            obj.pg_title = programData.title;
            obj.pg_synopsis = programData.synopsis;
            obj.pg_major_genre = programData.major_genre;
            obj.pg_minor_genre = programData.minor_genre;
            obj.pg_startdate = programData.start_date_time;
            obj.pg_enddate = programData.end_date_time;
            obj.pg_detail_url = programData.program_detail_url
        }
    }
    
    return obj;
};
