-- vim:set ft=lua:
dofile(mg.script_name:gsub('[^\\/]*$','')..'util.lua')

onair=GetVarInt(mg.request_info.query_string,'onair',0,1)==1
json=GetVarInt(mg.request_info.query_string,'json',0,1)==1

onid,tsid,sid,eid=GetVarEventID(mg.request_info.query_string,'id')
if eid==0 then
  onid,tsid,sid,startTime=GetVarPastEventID(mg.request_info.query_string,'id')
  if startTime==0 then
    onid,tsid,sid=GetVarServiceID(mg.request_info.query_string,'id')
  end
  if onid==65535 and tsid==65535 and sid==65535 then
    id=SelectChDataList(edcb.GetChDataList())
  else
    id={{onid=onid, tsid=tsid, sid=sid}}
  end
end

edcb.htmlEscape=json and 0 or 15
if onair then
  --放送中
  utc9Now=os.time()+9*3600
  b=edcb.EnumEventInfo(id,{startTime=os.date('!*t',utc9Now-24*3600), durationSecond=36*3600})

  if b and #b~=0 then
    table.sort(b,function(a,b) return (a.startTime and os.time(a.startTime) or 0)<(b.startTime and os.time(b.startTime) or 0) end)
    a={}
    for i,v in ipairs(b) do
      if v.startTime then
        startTime=TimeWithZone(v.startTime)
        if utc9Now<startTime then
          if a[1] and endTime~=startTime then
            a[2].durationSecond=startTime-endTime
          else
            a[2]=v
          end
          break
        elseif v.durationSecond and utc9Now<startTime+v.durationSecond then
          a[1]=v
          endTime=startTime+v.durationSecond
          a[2]={onid=onid, tsid=tsid, sid=sid, eid=0, startTime=os.date('!*t',endTime)}
        else
          w=v
        end
      end
    end
    if not a[1] then
      a[1]={onid=onid, tsid=tsid, sid=sid, eid=0}
      if w then
        if w.durationSecond then
          endTime=TimeWithZone(w.startTime)+w.durationSecond
          a[1].startTime=os.date('!*t',endTime)
          if a[2] then a[1].durationSecond=startTime-endTime end
        else
          a[1]=w
        end
      end
    end
  end
elseif eid>0 then
  --指定番組
  a={edcb.SearchEpg(onid, tsid, sid, eid)}
elseif startTime>0 then
  --過去番組
  et=edcb.EnumEventInfoArchive(id,{startTime=os.date('!*t',startTime), durationSecond=1})
  if et and #et~=0 then
    a={et[1]}
  end
else
  --一覧
  range=GetVarTimeRange(mg.request_info.query_string)
  a=edcb.EnumEventInfo(id,range)
  if range then
    for i,v in ipairs(edcb.EnumEventInfoArchive(id,range)) do
      v.past=true
      a[#a+1]=v
    end
    if a and #a~=0 then
      local function sortFunc(a, b)
        local at = a.startTime and os.time(a.startTime) or 0
        local bt = b.startTime and os.time(b.startTime) or 0
        if at ~= bt then return at < bt end
        return (a.sid or 0) < (b.sid or 0)
      end
      table.sort(a, sortFunc)

      -- 指定時刻跨ぎの番組を各サービスについて探す
      local range_t = os.time(range.startTime)
      local first_a = {}
      for i=1, #a do
        local v = a[i]
        local key = v.onid..'-'..v.tsid..'-'..v.sid
        if v.startTime and not first_a[key] then
          first_a[key] = os.time(v.startTime)
        end
      end

      local id_prev = {}
      for i=1, #id do
        local v = id[i]
        local key = v.onid..'-'..v.tsid..'-'..v.sid
        if first_a[key] ~= range_t then
          id_prev[#id_prev+1] = v
        end
      end

      if #id_prev > 0 then
        local prev_range = {startTime=os.date('!*t', TimeWithZone(range.startTime)-86400), durationSecond=86400}
        local b = edcb.EnumEventInfo(id_prev, prev_range)
        for _, v in ipairs(edcb.EnumEventInfoArchive(id_prev, prev_range)) do
          v.past = true
          b[#b+1] = v
        end

        local latest_b = {}
        for i=1, #b do
          local v = b[i]
          local key = v.onid..'-'..v.tsid..'-'..v.sid
          local t = v.startTime and os.time(v.startTime) or 0
          if t < range_t and (not latest_b[key] or t > latest_b[key]._t) then
            v._t = t
            latest_b[key] = v
          end
        end

        local added = false
        for _, v in pairs(latest_b) do
          -- range_tを跨いでいる（終了時間がrange_tより後）番組があれば追加
          if v.durationSecond and v._t + v.durationSecond > range_t then
            a[#a+1] = v
            added = true
          end
          v._t = nil
        end
        if added then
          table.sort(a, sortFunc)
        end
      end
    end
  end
end

if json then
  if a and #a~=0 then
    if eid>0 or startTime>0 then
      ResponseJson(a[1])
    else
      ResponseJson(a,mg.request_info.query_string)
    end
  else
    ResponseJson({err='EPGデータを読み込み中、または存在しません'})
  end
else
  ct=CreateContentBuilder()
  ct:Append('<?xml version="1.0" encoding="UTF-8" ?>')
  if not a or #a==0 then
    ct:Append('<entry><err>EPGデータを読み込み中、または存在しません</err></entry>')
  else
    basic=(GetVarInt(mg.request_info.query_string,'basic',0,1) or 1)~=0
    index=GetVarInt(mg.request_info.query_string,'index',0) or 0
    count=GetVarInt(mg.request_info.query_string,'count',0) or 200
    countTo=math.min(index+count,#a)
    service_name=GetServiceName(a[1]) or ''

    ct:Append('<entry><total>'..#a..'</total><index>'..index..'</index><count>'..math.max(countTo-index,0)..'</count><items>\r\n')
    for i=index+1,countTo do
      v=a[i]
      ct:Append('<eventinfo><ONID>'
        ..v.onid..'</ONID><TSID>'
        ..v.tsid..'</TSID><SID>'
        ..v.sid..'</SID><eventID>'
        ..v.eid..'</eventID><service_name>'
        ..service_name..'</service_name>')
      if v.startTime then
        ct:Append(string.format('<startDate>%d/%02d/%02d</startDate><startTime>%02d:%02d:%02d</startTime><startDayOfWeek>',
                                      v.startTime.year, v.startTime.month, v.startTime.day, v.startTime.hour, v.startTime.min, v.startTime.sec)
          ..(v.startTime.wday-1)..'</startDayOfWeek>')
      end
      if v.durationSecond then
        ct:Append('<duration>'..v.durationSecond..'</duration>')
      end
      if v.shortInfo then
        ct:Append('<event_name>'
          ..v.shortInfo.event_name..'</event_name><event_text>'
          ..v.shortInfo.text_char..'</event_text>')
      end
      if v.contentInfoList then
        for j,w in ipairs(v.contentInfoList) do
          nibble=w.content_nibble==0x0E00 and w.user_nibble+0x6000 or
                w.content_nibble==0x0E01 and w.user_nibble+0x7000 or w.content_nibble
          ct:Append('<contentInfo><nibble1>'
            ..math.floor(w.content_nibble / 256)..'</nibble1><nibble2>'
            ..(w.content_nibble % 256)..'</nibble2><component_type_name>'
            ..edcb.GetGenreName(math.floor(nibble/256)*256+255)..' - '..edcb.GetGenreName(nibble)..'</component_type_name></contentInfo>')
        end
      end
      if v.eventGroupInfo then
        for j,w in ipairs(v.eventGroupInfo.eventDataList) do
          ct:Append('<groupInfo><ONID>'
            ..w.onid..'</ONID><TSID>'
            ..w.tsid..'</TSID><SID>'
            ..w.sid..'</SID><eventID>'
            ..w.eid..'</eventID></groupInfo>')
        end
      end
      ct:Append('<freeCAFlag>'..(v.freeCAFlag and 1 or 0)..'</freeCAFlag>')
      if not basic then
        if v.extInfo then
          ct:Append('<event_ext_text>'..v.extInfo.text_char..'</event_ext_text>')
        end
        if v.componentInfo then
          ct:Append('<videoInfo><stream_content>'
            ..v.componentInfo.stream_content..'</stream_content><component_type>'
            ..v.componentInfo.component_type..'</component_type><component_tag>'
            ..v.componentInfo.component_tag..'</component_tag><text>'
            ..v.componentInfo.text_char..'</text><component_type_name>'
            ..edcb.GetComponentTypeName(v.componentInfo.stream_content*256+v.componentInfo.component_type)..'</component_type_name></videoInfo>')
        end
        if v.audioInfoList then
          for j,w in ipairs(v.audioInfoList) do
            ct:Append('<audioInfo><stream_content>'
              ..w.stream_content..'</stream_content><component_type>'
              ..w.component_type..'</component_type><component_tag>'
              ..w.component_tag..'</component_tag><stream_type>'
              ..w.stream_type..'</stream_type><simulcast_group_tag>'
              ..w.simulcast_group_tag..'</simulcast_group_tag><ES_multi_lingual_flag>'
              ..(w.ES_multi_lingual_flag and 1 or 0)..'</ES_multi_lingual_flag><main_component_flag>'
              ..(w.main_component_flag and 1 or 0)..'</main_component_flag><quality_indicator>'
              ..w.quality_indicator..'</quality_indicator><sampling_rate>'
              ..w.sampling_rate..'</sampling_rate><text>'
              ..w.text_char..'</text><component_type_name>'
              ..edcb.GetComponentTypeName(w.stream_content*256+w.component_type)..'</component_type_name></audioInfo>')
          end
        end
        if v.eventRelayInfo then
          for j,w in ipairs(v.eventRelayInfo.eventDataList) do
            local service_name=GetServiceName(w)
            ct:Append('<relayInfo><ONID>'
              ..w.onid..'</ONID><TSID>'
              ..w.tsid..'</TSID><SID>'
              ..w.sid..'</SID><eventID>'
              ..w.eid..'</eventID>'
              ..(service_name and '<service_name>'..service_name..'</service_name>' or '')
              ..'</relayInfo>')
          end
        end
      end
      ct:Append('</eventinfo>\r\n')
    end
    ct:Append('</items></entry>')
  end
  ct:Finish()
  mg.write(ct:Pop(Response(200,'text/xml','utf-8',ct.len)..'\r\n'))
end
