# This file is part of PSAMM.
#
# PSAMM 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.
#
# PSAMM 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 PSAMM.  If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2014-2017  Jon Lund Steffensen <jon_steffensen@uri.edu>
# Copyright 2016  Chao Liu <lcddzyx@gmail.com>
# Copyright 2015-2020  Keith Dufault-Thompson <keitht547@my.uri.edu>

"""Implementation of fastGapFill.

Described in [Thiele14]_.
"""

from __future__ import unicode_literals

import logging

from .fastcore import fastcore

logger = logging.getLogger(__name__)


def fastgapfill(model_extended, core, solver, weights={}, epsilon=1e-5):
    """Run FastGapFill gap-filling algorithm by calling
    :func:`psamm.fastcore.fastcore`.

    FastGapFill will try to find a minimum subset of reactions that includes
    the core reactions and it also has no blocked reactions.
    Return the set of reactions in the minimum subset. An extended model that
    includes artificial transport and exchange reactions can be generated by
    calling :func:`.create_extended_model`.

    Args:
        model: :class:`psamm.metabolicmodel.MetabolicModel`.
        core: reactions in the original metabolic model.
        weights: a weight dictionary for reactions in the model.
        solver: linear programming library to use.
        epsilon: float number, threshold for Fastcore algorithm.
    """

    # Run Fastcore and print the induced reaction set
    logger.info('Calculating Fastcore induced set on model')
    induced = fastcore(
        model_extended, core, epsilon=epsilon, weights=weights, solver=solver)
    logger.debug('Result: |A| = {}, A = {}'.format(len(induced), induced))
    added_reactions = induced - core
    logger.debug('Extended: |E| = {}, E = {}'.format(
        len(added_reactions), added_reactions))
    return induced
