package yukihane.coroid

import java.util.regex.Matcher
import java.util.regex.Pattern
import org.codehaus.groovy.grails.commons.ConfigurationHolder
import saccubus.ConvertStopFlag.StateChangeListener
import saccubus.net.TextProgressListener
import saccubus.prompt.Prompt
import nicobrowser.*
import yukihane.mediainfowrapper.*

class NicoContentService {

    boolean transactional = false
    def backgroundService

    def transcode(final NicoContent nc) {
        backgroundService.execute("Working for converting",{
            try{
                println 'CONVERTING: ' + nc.nicoId + ' ' + nc.name

                def mail = ConfigurationHolder.config.coroid.saccubus.mail
                def password = ConfigurationHolder.config.coroid.saccubus.password
                def mp4box = ConfigurationHolder.config.coroid.mp4box
                def mediainfo = ConfigurationHolder.config.coroid.mediainfo
                def ffmpegOption = ConfigurationHolder.config.coroid.ffmpeg.option
                def tempin = 'web-app/temp/in/'
                def tempout = 'web-app/temp/out/'
                def maxWidth = ConfigurationHolder.config.coroid.display.width
                def maxHeight = ConfigurationHolder.config.coroid.display.height
                def proxy = ConfigurationHolder.config.coroid.nicobrowser.proxy

                // ダウンロード処理
                def downloadListener = {long[] args ->
                    def progress = 100 * args[1] / args[0] as long
                    TranscodeStatusHolder.map().put(nc.id.toString(), 'D'+progress)
                } as ProgressListener
                def client = proxy ? new NicoHttpClient(proxy[0],proxy[1]) : new NicoHttpClient()
                def loggedin = client.login(mail, password)
                if(!loggedin){
                    throw new Exception("LOGIN FAILED")
                }
                def vi = client.getVideoInfo(nc.nicoId) as VideoInfo
                def video = client.getFlvFile(vi, tempin + nc.id + 'video', downloadListener)
                def comment = client.getCommentFile(vi, tempin + nc.id + 'comment')
                def tcomment = client.getTCommentFile(vi, tempin + nc.id + 'tcomment')

                // 画像サイズの判定
                def videoInfo = MediaInfo.getInfo(new File(mediainfo), video.getFile())
                def size = MediaInfo.adjustSize(videoInfo, maxWidth, maxHeight)
                println 'origianl size:'+videoInfo.getWidth()+'x'+videoInfo.getHeight()
                println 'adjusted size:'+size.getWidth()+'x'+size.getHeight()

                def output = tempout + nc.id + 'output.mp4'
                def sacc_cmd = [
                '-file_video', video.getFile().toString(),
                '-file_comment', comment.toString(),
                '-file_tcomment', tcomment.toString(),
                '-file_output', output,
                '-ffmpeg', ffmpegOption+' -s '+size.getWidth()+'x'+size.getHeight()] as String[]
                println sacc_cmd
                def tpl = new SaccubusListener(nc.id, nc.length)
                new Prompt().execute(sacc_cmd, tpl, StateChangeListener.EMPTY_LISTENER)

                def command = [new File(mp4box).toString(),
                '-hint',
                new File(output).toString()] as String[]

                Runtime.getRuntime().exec(command)
                nc.state = State.COMPLETED
                nc.save()

            }catch(e){
                e.printStackTrace()
                nc.state = State.ERROR
                nc.save()
            }finally{
                TranscodeStatusHolder.map().remove(nc.id.toString())
            }
            println 'COMPLETED: ' + nc.nicoId + ' ' + nc.name
        })
    }

    def listContents(final String url, final boolean split) {
        def rss = new XmlSlurper().parse(url)
        def allItems = rss.channel.item
        def rankingList = new ArrayList()
        Pattern thumbPattern = Pattern.compile('<p class="nico-thumbnail">.*?src="(.*?)"', Pattern.DOTALL)
        Pattern descPattern = Pattern.compile('<p class="nico-description">(.*?)</p>', Pattern.DOTALL)
        Pattern lengthPattern = Pattern.compile('<strong class="nico-info-length">(.*?)</strong>', Pattern.DOTALL)

        allItems.each{
            def name = (split) ? it.title.toString().split('：')[1] : it.title.toString()
            def id = it.link.toString().replace('http://www.nicovideo.jp/watch/', '')
            def description = it.description.toString()

            Matcher matcher

            matcher = thumbPattern.matcher(description)
            matcher.find()
            def nicoThumbnail = matcher.group(1)

            matcher = descPattern.matcher(description)
            matcher.find()
            def nicoDescription = matcher.group(1)

            matcher = lengthPattern.matcher(description)
            matcher.find()
            def nicoLength = matcher.group(1)

            def c = new NicoContent(nicoId: id, name: name, length: nicoLength,
                thumbnail: nicoThumbnail, description: nicoDescription)
            def f = NicoContent.findByNicoId(c.nicoId)
            if(f == null){
                def res = c.save()
                f = c
            }
            rankingList.add(f)
        }

        return rankingList
    }

    def getNicoContent(final String nicoId) {
        def thumb = null
        try{
            thumb = new NicoHttpClient().getThumbInfo(nicoId)
            def res = new XmlSlurper().parse(thumb).thumb[0]

            return new NicoContent(nicoId: nicoId, name: res.title[0].text(), length: res.length[0].text(),
                thumbnail: res.thumbnail_url[0].text(), description: res.description[0].text())
        }finally{
            thumb?.close()
        }
    }

    def splitList(list, requestPage){
        if(!list.size){
            return ['list':[], 'currentPage':1, 'totalPage':1, 'text':'']
        }

        def contentsPerPage = ConfigurationHolder.config.coroid.contentsPerPage
        def totalPage = list.size / contentsPerPage as int
        def splittedList = []
        for(i in 0..<totalPage){
            splittedList << list[contentsPerPage*i..(contentsPerPage*(i+1)-1)]
        }

        def numOflastPageElm = list.size % contentsPerPage
        if(numOflastPageElm > 0){
            splittedList << list[contentsPerPage*totalPage..-1]
            totalPage += 1
        }

        def currentPage = requestPage ?
            (requestPage.toInteger() <= splittedList.size ? requestPage.toInteger() : 1) : 1 as int

        def contStart = (currentPage-1)*contentsPerPage + 1
        def contEnd = contStart + splittedList[currentPage-1].size() - 1
        ['list':splittedList[currentPage-1], 'currentPage':currentPage, 'totalPage':totalPage,
            'text':"(${currentPage}/${totalPage}ページ ${contStart}-${contEnd}件目)"]
    }
}
