/***************************************************************************
**
**  This file is part of ArrayCore.
**
**  ArrayCore 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.
**
**  ArrayCore 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 Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2019-11-28
**  Copyright: 2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "ArrayTaskManager.h"
#include "AbstractArrayResults.h"

namespace ArrayCore {

  /*!
    \class ArrayTaskManager ArrayTaskManager.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  ArrayTaskManager::ArrayTaskManager(const ArrayStations * array)
    : TaskManager(), _array(array)
  {
    TRACE;
    _keep=nullptr;
    _parameters=nullptr;
    _results=nullptr;
  }

  /*!
    Description of destructor still missing
  */
  ArrayTaskManager::~ArrayTaskManager()
  {
    TRACE;
    delete _keep;
  }

  bool ArrayTaskManager::setParameters(const ArrayParameters * param)
  {
    TRACE;
    _parameters=param;
    _array.clear();
    _parameters->selectStations(_array);
    int n=_array.count();
    if(n>0) {
      App::log(1, tr("Found %1 distinct stations (local coordinates):\n%2")
                       .arg(n)
                       .arg(_array.toString(ArraySelection::Relative)));
    }

    const WindowingParameters& winParam=_parameters->windowing();
    // Only constant time window length is supported by arrays
    if((winParam.lengthType()!=WindowingParameters::Exactly &&
        winParam.lengthType()!=WindowingParameters::FrequencyDependent)) {
      App::log(tr("Only Exctly or FrequencyDependent time window lengths are supported\n"));
      return false;
    }
    if(winParam.maximumLength(1.0)<=0.0) {
      App::log(tr("Null time window length\n"));
      return false;
    }

    if(!setTimeLimits()) {
      return false;
    }
    setGlobalKeep();
    return true;
  }

  void ArrayTaskManager::setResults(AbstractArrayResults * res)
  {
    _results=res;
    _results->setArray(&_array);
  }

  /*!
    Initialization and validity tests specific to time limits. Returns false if it fails.
  */
  bool ArrayTaskManager::setTimeLimits()
  {
    if(_array.count()>0) {
      const StationSignals * stat=_array.at(0);
      TimeRange tw=_parameters->timeLimits().absoluteRange(stat);
      if(tw.lengthSeconds()<=0) {
        App::log(tr("Processing time length is null.\n") );
        return false;
      }
      return true;
    } else {
      App::log(tr("No station selected.\n") );
      return false;
    }
  }

  void ArrayTaskManager::setGlobalKeep()
  {
    int n=_array.count();
    // If there is no station selected, this function is not called (see setParameters() and setTimeLimits())
    ASSERT(n>0);
    // Collect ranges for all stations
    TimeRange r=_parameters->timeLimits().absoluteRange(_array.at(0));
    SparseTimeRange sr(r);
    for(int i=0; i<n; i++) {
      SparseTimeRange ssr=_array.at(i)->timeRange(r);
      if(!ssr.isNull()) {
        sr=sr.intersection(ssr);
      }
    }
    delete _keep;
    // The availibility of stations in time is checked before during selection of stations.
    // So null keep cannot occur if a station not available at all.
    _keep=new SparseKeepSignal(sr);
    // Adjust range taking sampling of all stations into account
    for(int i=0; i<n; i++) {
      _array.at(i)->setSampling(_keep);
    }
    // Set values of keep
    _keep->initValues(1);
    for(int i=0; i<n; i++) {
      _array.at(i)->setKeep(_keep, _parameters->windowing(), i);
    }
  }

  AbstractTask * ArrayTaskManager::createTask(int taskIndex)
  {
    TRACE;
    return new ArrayTask(this, taskIndex, &_array, _keep, _parameters);
  }

  void ArrayTaskManager::setTasks()
  {
    TRACE;
    TaskManager::setTasks(_parameters->frequencySampling().count());
  }

} // namespace ArrayCore

