package yukihane.coroid

import grails.converters.JSON
import nicobrowser.NicoHttpClient
import nicobrowser.search.*
import static yukihane.coroid.NicoVideoConst.*

class NicoContentController {
    def scaffold = true
    def nicoContentService

    def index = {
        redirect(action:ranking, params:[category:'all',kind:'fav',span:'daily',categoryTitle:'カテゴリ合算'])
    }

    def ranking = {
        def url = RANKING_URL+params.kind+'/'+params.span+'/'+params.category
        def rankingList = nicoContentService.listContents(url + '?rss=2.0',true)

        def splitResult = nicoContentService.splitList(rankingList, params.page)
        def pageLinks = []
        for(key in 1..splitResult.totalPage){
            def link = (splitResult.currentPage == key) ? ''+key :
                '<a href="'+createLink(action:'ranking',
                params:[category:params.category, kind:params.kind, span:params.span,
                categoryTitle:params.categoryTitle, page:key]) +
                '">' + key + '</a>'
            pageLinks << link
        }

        def title = "${params.categoryTitle} - ${KINDS[params.kind]} - ${SPANS[params.span]}" +
            "${splitResult.text}"

        render(template:'nicoContentListTemplate', model:[list:splitResult.list,
            progress:TranscodeStatusHolder.map(), title:title, pages:pageLinks])
    }

    // 個別動画参照ページ
    def watch = {
        def nicoId = params.id
        def nc = NicoContent.findByNicoId(nicoId)
        if(nc == null){
            nc = nicoContentService.getNicoContent(nicoId)
            nc.save()
        }

        render(template:'nicoContentListTemplate', model:[list:[nc], progress:TranscodeStatusHolder.map(),
            title: nc.name, pages:[]])
    }

    def mylist = {
        def mylist = params.id ? params.id : grailsApplication.config.coroid.mylist
        def url = MYLIST_URL + mylist
        def rankingList = nicoContentService.listContents(url  + '?sort=1&rss=2.0', false)

        def splitResult = nicoContentService.splitList(rankingList, params.page)
        def pageLinks = []
        for(key in 1..splitResult.totalPage){
            def link = (splitResult.currentPage == key) ? ''+key :
                '<a href="'+createLink(action:'mylist', params:[id:mylist, page:key]) +
                '">' + key + '</a>'
            pageLinks << link
        }

        def title = "マイリスト ${mylist} ${splitResult.text}"
        render(template:'nicoContentListTemplate', model:[list:splitResult.list,
            progress:TranscodeStatusHolder.map(), title:title, pages:pageLinks])
    }

    // 変換要求を行った履歴を表示する
    def history = {
        def contents = NicoContent.findAll("from NicoContent nc where nc.state != ? order by nc.lastUpdated desc",[State.NOTYET])
        def list = (contents.size <= 100) ? contents : contents[0..99]

        def splitResult = nicoContentService.splitList(list, params.page)
        def pageLinks = []
        for(key in 1..splitResult.totalPage){
            def link = (splitResult.currentPage == key) ? ''+key :
                '<a href="'+createLink(action:'history', params:[page:key]) +
                '">' + key + '</a>'
            pageLinks << link
        }

        def title = "履歴 ${splitResult.text}"

        render(template:'nicoContentListTemplate', model:[list:list,progress:TranscodeStatusHolder.map(),
            title:title, pages:pageLinks])
    }

    def search = {
        SearchKind kind = SearchKind.KeyWord
        for(v in SearchKind.values()){
            if(params.kind == v.getKey()){
                kind = v
                break
            }
        }

        SortKind sort = SortKind.MyListRegistration
        for(v in SortKind.values()){
            if(params.sort == v.getKey()){
                sort = v
                break
            }
        }

        SortOrder order = SortOrder.Descending
        for(v in SortOrder.values()){
            if(params.order == v.getKey()){
                order = v
                break
            }
        }

        int page = (params.page) ? Integer.parseInt(params.page) : 1

        def id = grailsApplication.config.coroid.saccubus.mail
        def password = grailsApplication.config.coroid.saccubus.password
        NicoHttpClient client = new NicoHttpClient()
        client.login(id, password)
        SearchResult result = client.search(kind, params.word, sort, order, page)
        
        def contents = []
        for(rc in result.getContents()){
            def nicoId = rc.getNicoId()
            def nc = NicoContent.findByNicoId(nicoId)
            if(nc == null){
                nc = nicoContentService.getNicoContent(nicoId)
                nc.save()
            }
            contents += nc
        }

        def pages = []
        for(key in result.getPages().keySet()){
            def link = '<a href="'+createLink(action:'search',
                params:[kind:params.kind,word:params.word,sort:params.sort,order:params.order,page:key]) +
                '">' + key+ '</a>'
            pages += link
        }
        def title = '検索:'+params.word+'('+page+')'

        render(template:'nicoContentListTemplate', model:[list:contents,progress:TranscodeStatusHolder.map(),
            title:title, pages:pages])
    }

    // 詳細情報ページ. javascript offでも動作するようhtmlをレンダリング.
    def detail = {
        def nc = NicoContent.get(params.id)
        def description = nc.description.encodeAsHTML()
//          .replaceAll(/mylist\/(\d+)/,'<a href="'+createLink(action:'mylist', id:'$1')+'">$0</a>')
            .replaceAll(/mylist\/(\d+)/,'<a href="'+createLink(action:'mylist')+'/$1">$0</a>')
            .replaceAll(/(sm|nm)(\d+)/,'<a href="'+createLink(action:'watch')+'/$0">$0</a>')
        if(grailsApplication.config.coroid.externallink){
            // 外部リンクは相手サーバにリファラが残るのでオプションとする。
            description = description.replaceAll(/http:\/\/(([-\/\.~_%\?=&\w])+\/*)+/, '<a href="$0">$0</a>')
            description += '<hr /><a href="http://www.nicomimi.net/play/' +
                nc.nicoId + '" target="_blank">nicomimi</a>' +
                ' <a href="http://nicosound.anyap.info/sound/' + nc.nicoId +'" target="_blank">さうんど</a>'
        }

        render('<html><body><a href="'+createLink(action:'add_mylist',id:nc.nicoId)+'">'
            +'<img src="'+nc.thumbnail+'" align="left" alt="サムネイル画像クリックでマイリスト登録"  width="92" height="69"/></a>'
            +'<small><b>'+nc.nicoId+'</b> '+description+'</small></body></html>')
    }

    // トランスコードステータス. javascript onの時のみ必要なのでJSONで返す.
    def state = {
        def nc = NicoContent.get(params.id)
        def status
        if(nc?.state == State.LOADING){
            status = TranscodeStatusHolder.map().get(nc.id.toString())
            if(!status){
                status = nc.state.getText()
            }
        } else {
            status = nc.state.getText()
        }

        def result = [status:status]
        if(nc?.state == State.COMPLETED){
            result.playUrl = createLink(action:"play", params:[id: nc.id])
        }
        render result as JSON
    }

    def play = {
        def url = '/coroid/temp/out/' + params.id + 'output.mp4'
        redirect(url:url)
    }

    def convert = {
        def nc = NicoContent.get(params.id)
        if(nc.state == State.NOTYET || nc.state == State.ERROR){
            nc.state = State.LOADING
            nc.save()
            nicoContentService.transcode(nc)
        }

        def referer = request?.getHeader('referer')
        if(referer) {
            redirect(url: referer)
        } else {
            redirect(action: 'index')
        }
    }

    def add_mylist = {
        def nicoId = params.id
        println('マイリスト登録: ' + nicoId)

        def id = grailsApplication.config.coroid.saccubus.mail
        def password = grailsApplication.config.coroid.saccubus.password
        def mylist = grailsApplication.config.coroid.mylist
        NicoHttpClient client = new NicoHttpClient()
        client.login(id, password)
        client.addMyList(mylist, nicoId)
        def url = 'http://www.nicovideo.jp/mylist/' + mylist + '?sort=1&rss=2.0'
        nicoContentService.listContents(url, false)
        def nc = NicoContent.findByNicoId(nicoId)
        if(nc != null && nc.state == State.NOTYET){
            nc.state = State.LOADING
            nc.save()
            nicoContentService.transcode(nc)
        }
        redirect(action:'mylist')
    }
}
