/*
 * WallaRead - A Wallabag 2+ client for SailfishOS
 * © 2016 Grégory Oestreicher <greg@kamago.net>
 *
 * This file is part of WallaRead.
 *
 * WallaRead 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.
 *
 * WallaRead 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 WallaRead.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

import QtQuick 2.0
import harbour.wallaread 1.0

import "../js/WallaBase.js" as WallaBase

Item {
    id: server

    property int serverId: -1
    property string name
    property string url
    property int lastSync: 0
    property string accessToken
    property string refreshToken
    property string tokenType
    property int tokenExpiry: 0
    property bool fetchUnread: false

    signal articlesDownloaded( var list )
    signal connected
    signal error( string message )

    onServerIdChanged: {
        if ( serverId !== -1 ) {
            console.debug( "Loading information for server " + serverId )
            WallaBase.getServer( serverId, onServerLoaded )
        }
        else {
            name = null
            url = null
            lastSync = 0
            accessToken = null
            refreshToken = null
            tokenType = null
            tokenExpiry = 0
            fetchUnread = false
        }
    }

    HttpRequester {
        id: httpRequester
    }

    function onServerLoaded( props, err ) {
        if ( err !== null ) {
            error( qsTr( "Failed to load server information: " ) + err )
        }
        else {
            name = props.name
            url = props.url
            lastSync = props.lastSync
            fetchUnread = props.fetchUnread === 1
        }
    }

    function connect( cb ) {
        var now = Math.floor( (new Date).getTime() / 1000 )
        if ( tokenExpiry <= now ) {
            console.debug( "Opening connection for server " + serverId )
            WallaBase.connectToServer(
                serverId,
                function( props, err ) {
                    onConnectionDone( props, err, cb )
                }
            )
        }
        else {
            cb( null );
        }
    }

    function onConnectionDone( props, err, cb ) {
        if ( err === null ) {
            console.debug( "Successfully connected to server " + serverId )
            accessToken = props.access_token
            refreshToken = props.refresh_token
            tokenType = props.token_type
            tokenExpiry = Math.floor( (new Date).getTime() / 1000 ) + props.expires_in
        }

        cb( err )
    }

    function isConnected() {
        return tokenExpiry > Math.floor( (new Date).getTime() / 1000 )
    }

    function syncDeletedArticles( cb ) {
        connect(
            function( err ) {
                if ( err !== null ) {
                    error( qsTr( "Failed to connect to server: " ) + err )
                    cb()
                }
                else {
                    WallaBase.syncDeletedArticles( { id: serverId, token: accessToken, url: url }, function() { cb(); } )
                }
            }
        )
    }

    // No need for a callback here as the articlesDownloaded() signal will
    // be emitted if there are any changes.
    function getUpdatedArticles() {
        connect(
            function( err ) {
                if ( err !== null ) {
                    error( qsTr( "Failed to connect to server: " ) + err)
                    articlesDownloaded( [] )
                }
                else {
                    console.debug( "Downloading articles changes since last sync" )
                    var props = { url: url, since: lastSync, accessToken: accessToken, archive: fetchUnread ? 1 : 0 }
                    WallaBase.downloadArticles( props, onGetUpdatedArticlesDone )
                }
            }
        )
    }

    function onGetUpdatedArticlesDone( articles, err ) {
        var ret = new Array;

        if ( err !== null ) {
            error( qsTr( "Failed to download articles: " ) + err )
        }
        else {
            console.debug( "Retrieved " + articles.length + " new/updated articles" )

            for ( var i = 0; i < articles.length; ++i ) {
                var current = articles[i];
                var article = {
                    id: current.id,
                    server: serverId,
                    created: current.created_at,
                    updated: current.updated_at,
                    mimetype: current.mimetype,
                    language: current.language,
                    readingTime: current.reading_time,
                    url: current.url,
                    domain: current.domain_name,
                    archived: current.is_archived,
                    starred: current.is_starred,
                    title: current.title,
                    previewPicture: current.previewPicture,
                    content: current.content
                }
                WallaBase.saveArticle( article )
                ret.push( article )
            }

            WallaBase.setServerLastSync( serverId, Math.floor( (new Date).getTime() / 1000 ) )
        }

        articlesDownloaded( ret )
    }

    function uploadArticle( articleUrl, cb ) {
        connect(
            function( err ) {
                if ( err !== null ) {
                    error( qsTr( "Failed to connect to server: " ) + err )
                    cb( false )
                }
                else {
                    console.debug( "Sending a new article" )
                    var props = { url: url, token: accessToken }
                    WallaBase.uploadNewArticle(
                        props,
                        articleUrl,
                        function( content, err ) {
                            onUploadArticleDone( content, err )
                            cb( err === null )
                        }
                    )
                }
            }
        )
    }

    function onUploadArticleDone( current, err ) {
        if ( err !== null ) {
            error( qsTr( "Failed to upload article: " ) + err )
        }
        else {
            var article = {
                id: current.id,
                server: serverId,
                created: current.created_at,
                updated: current.updated_at,
                mimetype: current.mimetype,
                language: current.language,
                readingTime: current.reading_time,
                url: current.url,
                domain: current.domain_name,
                archived: current.is_archived,
                starred: current.is_starred,
                title: current.title,
                previewPicture: current.previewPicture,
                content: current.content
            }
            WallaBase.saveArticle( article )
        }

        articlesDownloaded( [] )
    }

    function toggleArticleStar( article, cb ) {
        connect(
            function( err ) {
                if ( err !== null ) {
                    error( qsTr( "Failed to connect to server: " ) + err );
                    cb( false )
                }
                else {
                    var articleUrl = url
                    if ( articleUrl.charAt( articleUrl.length - 1 ) !== "/" )
                        articleUrl += "/"
                    articleUrl += "api/entries/" + article.id + ".json"

                    var json = {}
                    json.starred = ( article.starred ? 0 : 1 )

                    console.debug( "Setting starred to " + json.starred + " on article " + article.id )

                    httpRequester.patch(
                        articleUrl,
                        accessToken,
                        JSON.stringify( json ),
                        function( patchResponse, patchError ) {
                            onToggleArticleStarDone( patchResponse, patchError, article )
                            cb( patchError === null )
                        }
                    )
                }
            }
        )
    }

    function onToggleArticleStarDone( content, err, article ) {
        if ( err !== null ) {
            error( qsTr( "Failed to set star status on article: " ) + err )
        }
        else {
            console.debug( "Done toggling starred status for article " + article.id )
            var json = JSON.parse( content )
            WallaBase.setArticleStar( serverId, article.id, json.is_starred )
        }
    }

    function toggleArticleRead( article, cb ) {
        connect(
            function( err ) {
                if ( err !== null ) {
                    error( qsTr( "Failed to connect to server: " ) + err )
                    cb( false )
                }
                else {
                    var articleUrl = url
                    if ( articleUrl.charAt( articleUrl.length - 1 ) !== "/" )
                        articleUrl += "/"
                    articleUrl += "api/entries/" + article.id + ".json"

                    var json = {}
                    json.archive = ( article.archived ? 0 : 1 )

                    console.debug( "Setting archived to " + json.archived + " on article " + article.id )

                    httpRequester.patch(
                        articleUrl,
                        accessToken,
                        JSON.stringify( json ),
                        function( patchResponse, patchError ) {
                            onToggleArticleReadDone( patchResponse, patchError, article )
                            cb( patchError === null )
                        }
                    )
                }
            }
        )
    }

    function onToggleArticleReadDone( content, err, article, cb ) {
        if ( err !== null ) {
            error( qsTr( "Failed to set read status on article: " ) + err )
        }
        else {
            console.debug( "Done toggling archived status for article " + article.id )
            var json = JSON.parse( content )
            WallaBase.setArticleRead( serverId, article.id, json.is_archived )
        }
    }

    function deleteArticle( id, cb ) {
        connect(
            function( err ) {
                if ( err !== null ) {
                    error( qsTr( "Failed to connect to server: " ) + err )
                    cb( false )
                }
                else {
                    var articleUrl = url
                    if ( articleUrl.charAt( articleUrl.length - 1 ) !== "/" )
                        articleUrl += "/"
                    articleUrl += "api/entries/" + id + ".json"

                    console.debug( "Deleting article " + id )

                    httpRequester.del(
                        articleUrl,
                        accessToken,
                        function( delResponse, delError ) {
                            onDeleteArticleDone( delResponse, delError, id )
                            cb( err === null )
                        }

                    )
                }
            }
        )
    }

    function onDeleteArticleDone( content, err, id, cb ) {
        if ( err !== null ) {
            error( qsTr( "Failed to delete article: " ) + err )
        }
        else {
            console.debug( "Done deleting article " + id )
            WallaBase.deleteArticle( serverId, id )
        }
    }
}
