# -*- coding: utf-8 -*-
#
# Copyright 2012-2020 BigML
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""BigMLer - main processing dispatching

"""


import sys
import os
import re
import gc

import bigml.api

from bigml.model import Model
from bigml.basemodel import retrieve_resource
from bigml.fields import Fields

import bigmler.utils as u
import bigmler.resourcesapi.common as r
import bigmler.resourcesapi.datasets as rds
import bigmler.resourcesapi.ensembles as rens
import bigmler.resourcesapi.models as rmod
import bigmler.resourcesapi.batch_predictions as rbp
import bigmler.labels as l
import bigmler.processing.args as a
import bigmler.processing.sources as ps
import bigmler.processing.datasets as pd
import bigmler.processing.models as pm

from bigmler.evaluation import evaluate, cross_validate
from bigmler.defaults import DEFAULTS_FILE
from bigmler.prediction import predict, combine_votes, remote_predict
from bigmler.prediction import OTHER, COMBINATION
from bigmler.reports import clear_reports, upload_reports
from bigmler.command import get_context
from bigmler.command import COMMAND_LOG, DIRS_LOG, SESSIONS_LOG


LOG_FILES = [COMMAND_LOG, DIRS_LOG, u.NEW_DIRS_LOG]
MINIMUM_MODEL = "full=false"

DEFAULT_OUTPUT = 'predictions.csv'

SETTINGS = {
    "command_log": COMMAND_LOG,
    "sessions_log": SESSIONS_LOG,
    "dirs_log": DIRS_LOG,
    "default_output": DEFAULT_OUTPUT,
    "defaults_file": DEFAULTS_FILE}


def belongs_to_ensemble(model):
    """Checks if a model is part of an ensemble

    """
    return ('object' in model and 'ensemble' in model['object'] and
            model['object']['ensemble'])


def get_ensemble_id(model):
    """Returns the ensemble/id for a model that belongs to an ensemble

    """
    if 'object' in model and 'ensemble_id' in model['object']:
        return "ensemble/%s" % model['object']['ensemble_id']
    return None


def get_metadata(resource, key, default_value):
    """Retrieves from the user_metadata key in the resource the
       given key using default_value as a default

    """
    if ('object' in resource and 'user_metadata' in resource['object'] and
            key in resource['object']['user_metadata']):
        return resource['object']['user_metadata'][key]
    return default_value


def has_source(args):
    """Checks whether the command options include a source or a previous
       training file
    """
    return (args.training_set or args.source or args.source_file or
            args.train_stdin)


def clear_log_files(log_files):
    """Clear all contents in log files

    """
    for log_file in log_files:
        try:
            open(log_file, 'wb', 0).close()
        except IOError:
            pass


def get_test_dataset(args):
    """Returns the dataset id from one of the possible user options:
       --test-dataset --test-datasets

    """
    args.test_dataset_ids = []
    try:
        # Parses dataset/id if provided.
        if args.test_datasets:
            args.test_dataset_ids = u.read_datasets(args.test_datasets)
    except AttributeError:
        pass
    return (args.test_dataset if args.test_dataset is not None
            else None if not args.test_dataset_ids
            else args.test_dataset_ids[0])


def get_objective_id(args, fields):
    """Returns the objective id set by the user or the default

    """
    if args.objective_field is not None:
        try:
            objective_id = u.get_objective_id(fields, args.objective_field)
            fields.update_objective_field(
                fields.field_column_number(objective_id), True)
        except (KeyError, ValueError) as exc:
            sys.exit(exc)
    else:
        return fields.field_id(fields.objective_field)
    return objective_id


def check_args_coherence(args):
    """Checks the given options for coherence and completitude

    """
    # It is compulsory to have a description to publish either datasets or
    # models
    if (not args.description_ and
            (args.black_box or args.white_box or args.public_dataset)):
        sys.exit("You should provide a description to publish.")

    # When using --max-categories, it is compulsory to specify also the
    # objective_field
    if args.max_categories > 0 and args.objective_field is None:
        sys.exit("When --max-categories is used, you must also provide the"
                 " --objective field name or column number")

    # When using --new-fields, it is compulsory to specify also a dataset
    # id
    if args.new_fields and not args.dataset:
        sys.exit("To use --new-fields you must also provide a dataset id"
                 " to generate the new dataset from it.")
    # The --median option is only available for local predictions, not for
    # remote ones.
    if args.median and args.remote:
        args.median = False
        print ("WARNING: the --median option is only available for local"
               " predictions. Using the mean value in the predicted node"
               " instead.")


def main_dispatcher(args=sys.argv[1:]):
    """Parses command line and calls the different processing functions

    """

    # If --clear-logs the log files are cleared
    if "--clear-logs" in args:
        clear_log_files(LOG_FILES)

    settings = {}