//jDownloader - Downloadmanager
//Copyright (C) 2009  JD-Team support@jdownloader.org
//
//This program 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.
//
//This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
package jd.plugins.hoster;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;

import jd.PluginWrapper;
import jd.http.Browser;
import jd.http.Cookies;
import jd.nutils.encoding.Encoding;
import jd.parser.Regex;
import jd.parser.html.Form;
import jd.plugins.Account;
import jd.plugins.Account.AccountType;
import jd.plugins.AccountInfo;
import jd.plugins.DownloadLink;
import jd.plugins.DownloadLink.AvailableStatus;
import jd.plugins.HostPlugin;
import jd.plugins.LinkStatus;
import jd.plugins.PluginException;
import jd.plugins.PluginForHost;

@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = {}, urls = {})
public class File2btcCom extends PluginForHost {
    public File2btcCom(PluginWrapper wrapper) {
        super(wrapper);
        this.enablePremium("http://file2btc.com/join.php?return=");
    }

    @Override
    public String getAGBLink() {
        return "http://file2btc.com/contact.php";
    }

    private static List<String[]> getPluginDomains() {
        final List<String[]> ret = new ArrayList<String[]>();
        // each entry in List<String[]> will result in one PluginForHost, Plugin.getHost() will return String[0]->main domain
        ret.add(new String[] { "file2btc.com" });
        return ret;
    }

    public static String[] getAnnotationNames() {
        return buildAnnotationNames(getPluginDomains());
    }

    @Override
    public String[] siteSupportedNames() {
        return buildSupportedNames(getPluginDomains());
    }

    public static String[] getAnnotationUrls() {
        final List<String> ret = new ArrayList<String>();
        for (final String[] domains : getPluginDomains()) {
            ret.add("https?://(?:www\\.)?" + buildHostsPatternPart(domains) + "/file\\.([A-Za-z0-9]+)");
        }
        return ret.toArray(new String[0]);
    }

    /* Connection stuff */
    private final boolean FREE_RESUME                  = true;
    private final int     FREE_MAXCHUNKS               = -4;
    private final int     FREE_MAXDOWNLOADS            = -1;
    private final boolean ACCOUNT_FREE_RESUME          = true;
    private final int     ACCOUNT_FREE_MAXCHUNKS       = -4;
    private final int     ACCOUNT_FREE_MAXDOWNLOADS    = -1;
    private final boolean ACCOUNT_PREMIUM_RESUME       = true;
    private final int     ACCOUNT_PREMIUM_MAXCHUNKS    = -4;
    private final int     ACCOUNT_PREMIUM_MAXDOWNLOADS = -1;

    @Override
    public String getLinkID(final DownloadLink link) {
        final String linkid = getFID(link);
        if (linkid != null) {
            return this.getHost() + "://" + linkid;
        } else {
            return super.getLinkID(link);
        }
    }

    private String getFID(final DownloadLink link) {
        return new Regex(link.getPluginPatternMatcher(), this.getSupportedLinks()).getMatch(0);
    }

    @Override
    public AvailableStatus requestFileInformation(final DownloadLink link) throws IOException, PluginException {
        br.setFollowRedirects(true);
        br.getPage(link.getPluginPatternMatcher());
        if (this.br.getHttpConnection().getResponseCode() == 404) {
            throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
        } else if (br.getRequest().getHtmlCode().equalsIgnoreCase("File Not Found")) {
            throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
        }
        final String originalFilename = br.getRegex("<font size='3' color='grey'>([^<]+)</font><br>").getMatch(0);
        if (!StringUtils.isEmpty(originalFilename)) {
            link.setName(Encoding.htmlDecode(originalFilename).trim());
        } else {
            String filetitle = br.getRegex("div style=\"height: 45px;\">([^<]+)</div>").getMatch(0);
            if (filetitle == null) {
                filetitle = br.getRegex("<title>([^<]+)</title>").getMatch(0);
            }
            if (!StringUtils.isEmpty(filetitle)) {
                filetitle = Encoding.htmlDecode(filetitle.trim());
                /* Add missing file-extension for videos if needed. */
                if (br.containsHTML("type=\"video/mp4\"")) {
                    filetitle = this.correctOrApplyFileNameExtension(filetitle, ".mp4");
                }
                link.setName(filetitle);
            }
        }
        final String filesize = br.getRegex("(?i)>\\s*Size:\\s*<b>([^<]+)</b>").getMatch(0);
        if (!StringUtils.isEmpty(filesize)) {
            link.setDownloadSize(SizeFormatter.getSize(filesize));
        }
        return AvailableStatus.TRUE;
    }

    @Override
    public void handleFree(final DownloadLink link) throws Exception, PluginException {
        handleDownload(link, null, FREE_RESUME, FREE_MAXCHUNKS, "free_directlink");
    }

    private void handleDownload(final DownloadLink link, final Account account, final boolean resumable, final int maxchunks, final String directlinkproperty) throws Exception, PluginException {
        if (account != null) {
            this.login(account, true);
        }
        String dllink = link.getStringProperty(directlinkproperty);
        if (dllink != null) {
            /* Try to re-use stored directurl */
            try {
                dl = jd.plugins.BrowserAdapter.openDownload(br, link, dllink, resumable, maxchunks);
                if (this.looksLikeDownloadableContent(dl.getConnection())) {
                    dl.startDownload();
                    return;
                }
            } catch (final Throwable e) {
                logger.log(e);
                try {
                    dl.getConnection().disconnect();
                } catch (Throwable ignore) {
                }
            }
            link.removeProperty(directlinkproperty);
        }
        requestFileInformation(link);
        final String limitWaitMinutesStr = br.getRegex("(?i)>\\s?You have to wait\\s*<b>(\\d+)</b>\\s*minutes?").getMatch(0);
        if (limitWaitMinutesStr != null) {
            throw new PluginException(LinkStatus.ERROR_IP_BLOCKED, Long.parseLong(limitWaitMinutesStr) * 60 * 1001l);
        }
        if (account != null) {
            dllink = br.getRegex("<a href=\"(https?://[^\"]+)\" download>").getMatch(0);
            if (dllink != null) {
                /* Wait one second otherwise that URL won't work yet. */
                this.sleep(1000, link);
            } else {
                /* API. Does pretty much the same as website. Docs: http://file2btc.com/api.php */
                /* 2022-09-27: Seems like when using the API we only get free user speeds? */
                br.getPage("/commands/api.php?hash=" + this.getFID(link));
                this.sleep(1000, link);
                dllink = "/download.php?secure=" + br.getRequest().getHtmlCode();
            }
        } else {
            /* 2022-09-26: Pre-download waittime can be skipped. */
            final String dllinkBase = br.getRegex("use <a href=.(https?://[^<>\"\\']+=)").getMatch(0);
            if (dllinkBase == null) {
                throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
            }
            br.postPage("/commands/download.php", "hash=" + this.getFID(link));
            this.sleep(1000, link);
            dllink = dllinkBase + br.getRequest().getHtmlCode();
        }
        dl = jd.plugins.BrowserAdapter.openDownload(br, link, dllink, resumable, maxchunks);
        if (!this.looksLikeDownloadableContent(dl.getConnection())) {
            if (dl.getConnection().getResponseCode() == 403) {
                throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "Server error 403", 60 * 60 * 1000l);
            } else if (dl.getConnection().getResponseCode() == 404) {
                throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "Server error 404", 60 * 60 * 1000l);
            }
            try {
                br.followConnection(true);
            } catch (final IOException e) {
                logger.log(e);
            }
            throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
        }
        link.setProperty(directlinkproperty, dl.getConnection().getURL().toString());
        dl.startDownload();
    }

    @Override
    public int getMaxSimultanFreeDownloadNum() {
        return FREE_MAXDOWNLOADS;
    }

    private boolean login(final Account account, final boolean force) throws Exception {
        synchronized (account) {
            try {
                br.setFollowRedirects(true);
                br.setCookiesExclusive(true);
                final Cookies cookies = account.loadCookies("");
                if (cookies != null) {
                    logger.info("Attempting cookie login");
                    this.br.setCookies(this.getHost(), cookies);
                    if (!force) {
                        /* Don't validate cookies */
                        return false;
                    }
                    br.getPage("https://" + this.getHost() + "/dashboard.php");
                    if (this.isLoggedin(br)) {
                        logger.info("Cookie login successful");
                        /* Refresh cookie timestamp */
                        account.saveCookies(this.br.getCookies(this.getHost()), "");
                        return true;
                    } else {
                        logger.info("Cookie login failed");
                    }
                }
                logger.info("Performing full login");
                br.getPage("http://" + this.getHost() + "/login.php?return=");
                Form loginform = null;
                for (final Form form : br.getForms()) {
                    if (form.containsHTML("captcha\\.php")) {
                        loginform = form;
                        break;
                    }
                }
                if (loginform == null) {
                    throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
                }
                loginform.put("myusername", Encoding.urlEncode(account.getUser()));
                loginform.put("password1", Encoding.urlEncode(account.getPass()));
                final String code = this.getCaptchaCode("/captcha.php", getDownloadLink());
                loginform.put("captcha", Encoding.urlEncode(code));
                br.submitForm(loginform);
                if (!isLoggedin(br)) {
                    throw new PluginException(LinkStatus.ERROR_PREMIUM, PluginException.VALUE_ID_PREMIUM_DISABLE);
                }
                account.saveCookies(this.br.getCookies(this.getHost()), "");
                return true;
            } catch (final PluginException e) {
                if (e.getLinkStatus() == LinkStatus.ERROR_PREMIUM) {
                    account.clearCookies("");
                }
                throw e;
            }
        }
    }

    private boolean isLoggedin(final Browser br) {
        return br.containsHTML("logout\\.php");
    }

    @Override
    public AccountInfo fetchAccountInfo(final Account account) throws Exception {
        final AccountInfo ai = new AccountInfo();
        login(account, true);
        final String spaceUsed = br.getRegex("Storage:\\s*<br>\\s*<font [^>]*>\\s*(\\d+ [^/<]+)").getMatch(0);
        if (spaceUsed != null) {
            ai.setUsedSpace(spaceUsed.trim());
        }
        final Regex trafficToday = br.getRegex("Traffic Today:\\s*<br>\\s*<font [^>]*>\\s*(\\d+ [^/]+)/([^<]+)");
        final String trafficUsed = trafficToday.getMatch(0);
        final String trafficMax = trafficToday.getMatch(1);
        if (trafficUsed == null || trafficMax == null) {
            throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
        }
        ai.setTrafficMax(SizeFormatter.getSize(trafficMax));
        ai.setTrafficLeft(ai.getTrafficMax() - SizeFormatter.getSize(trafficUsed));
        /* 2022-09-26: Premium accounts are not yet supported */
        final boolean isPremium = br.containsHTML("(?i)Account Type\\s*:\\s*<br>\\s*<font[^>]+>\\s*<font[^>]*><b>Premium");
        if (isPremium) {
            final String expireStr = br.getRegex("(?i)Premium Expires:\\s*<br>\\s*<font[^>]*>\\s*([^<]*?)\\s*</font>").getMatch(0);
            if (StringUtils.equalsIgnoreCase(expireStr, "Lifetime")) {
                account.setType(AccountType.LIFETIME);
            } else {
                account.setType(AccountType.PREMIUM);
            }
            account.setMaxSimultanDownloads(ACCOUNT_PREMIUM_MAXDOWNLOADS);
        } else {
            account.setType(AccountType.FREE);
            account.setMaxSimultanDownloads(ACCOUNT_FREE_MAXDOWNLOADS);
        }
        return ai;
    }

    @Override
    public void handlePremium(final DownloadLink link, final Account account) throws Exception {
        if (account.getType() == AccountType.PREMIUM || account.getType() == AccountType.LIFETIME) {
            handleDownload(link, account, ACCOUNT_PREMIUM_RESUME, ACCOUNT_PREMIUM_MAXCHUNKS, "premium_directlink");
        } else {
            handleDownload(link, account, ACCOUNT_FREE_RESUME, ACCOUNT_FREE_MAXCHUNKS, "account_free_directlink");
        }
    }

    @Override
    public int getMaxSimultanPremiumDownloadNum() {
        return ACCOUNT_PREMIUM_MAXDOWNLOADS;
    }

    @Override
    public boolean hasCaptcha(final DownloadLink link, final Account acc) {
        /* Captchas are only needed for account login */
        return false;
    }

    @Override
    public void reset() {
    }

    @Override
    public void resetDownloadlink(DownloadLink link) {
    }
}