/* TA-LIB Copyright (c) 1999-2025, Mario Fortier
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * - Neither name of author nor the names of its contributors
 *   may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* Important:
 *  This file is automatically generated by the utility ta_codegen.
 *  Any modifications will be lost on next execution of ta_codegen.
 *
 *  Modifications should instead be done with the "C" source file
 *  in ta-lib\src\ta_func
 */

/* List of contributors:
 *
 *  Initial  Name/description
 *  -------------------------------------------------------------------
 *  MF       Mario Fortier
 *  PP       Peter Pudaite
 *  AA       Andrew Atkinson
 *
 * Change history:
 *
 *  MMDDYY BY   Description
 *  -------------------------------------------------------------------
 *  120802 MF   Template creation.
 *  101103 PP   Initial creation of code.
 *  112603 MF   Add independent control to the RSI period.
 *  020605 AA   Fix #1117656. NULL pointer assignement.
 */

// Import types from parent module
use super::*;

// Allow non-snake-case names to maintain TA-Lib API compatibility
#[allow(non_snake_case)]
#[allow(unused_variables)]
#[allow(dead_code)]
#[allow(unused_mut)]
#[allow(unused_assignments)]
impl Core {
    /// Lookback period for [`Core::stochrsi`]: the number of leading input values consumed before
    /// the first output value can be produced.
    ///
    /// # Arguments
    ///
    /// * `optInTimePeriod` — RSI period (default 14, range 2..=100000)
    /// * `optInFastK_Period` — Lookback window for the RSI min/max stochastic (default 5, range
    ///   1..=100000)
    /// * `optInFastD_Period` — Smoothing period for %D (default 3, range 1..=100000)
    /// * `optInFastD_MAType` — MA type used to smooth %D (default 0 = SMA, values: 0=SMA, 1=EMA,
    ///   2=WMA, 3=DEMA, 4=TEMA, 5=TRIMA, 6=KAMA, 7=MAMA, 8=T3)
    ///
    /// Returns `usize::MAX` when a parameter is out of range. Integer parameters accept `i32::MIN`
    /// to select their default value.
    #[inline]
    pub fn stochrsi_lookback(&self, mut optInTimePeriod: i32, mut optInFastK_Period: i32, mut optInFastD_Period: i32, mut optInFastD_MAType: i32) -> usize {
        if ((optInTimePeriod) as i32) == (i32::MIN) {
            optInTimePeriod = 14;
        } else if (((optInTimePeriod) as i32) < 2) || (((optInTimePeriod) as i32) > 100000) {
            return usize::MAX;
        }
        if ((optInFastK_Period) as i32) == (i32::MIN) {
            optInFastK_Period = 5;
        } else if (((optInFastK_Period) as i32) < 1) || (((optInFastK_Period) as i32) > 100000) {
            return usize::MAX;
        }
        if ((optInFastD_Period) as i32) == (i32::MIN) {
            optInFastD_Period = 3;
        } else if (((optInFastD_Period) as i32) < 1) || (((optInFastD_Period) as i32) > 100000) {
            return usize::MAX;
        }
        let mut retValue: usize = 0_usize;
        retValue = self.rsi_lookback(optInTimePeriod) + self.stochf_lookback(optInFastK_Period, optInFastD_Period, optInFastD_MAType);
        return retValue;
    }
    /// Applies the Fast Stochastic (STOCHF) oscillator to an RSI series instead of price, measuring
    /// where RSI sits within its recent min/max range. Oscillates 0-100; high = RSI near its recent
    /// top, low = near its recent bottom.
    ///
    /// # Formula
    ///
    /// ```text
    /// rsi = RSI(inReal, optInTimePeriod)
    /// FastK = 100 * (rsi_t - min(rsi, FastK_Period)) / (max(rsi, FastK_Period) - min(rsi, FastK_Period))
    /// FastD = MA(FastK, FastD_Period, FastD_MAType)
    /// ```
    ///
    /// # Notes
    ///
    /// * To reproduce the original article's unsmoothed Stochastic RSI, set the RSI period equal to
    ///   the %K period and read the raw %K output.
    /// * When the RSI's recent range is zero, %K is set to 0 instead of being undefined.
    ///
    /// # Arguments
    ///
    /// * `startIdx` — Start index of the requested calculation range.
    /// * `endIdx` — End index of the requested calculation range (inclusive).
    /// * `inReal` — Source series fed into the RSI calculation.
    /// * `optInTimePeriod` — RSI period (default 14, range 2..=100000)
    /// * `optInFastK_Period` — Lookback window for the RSI min/max stochastic (default 5, range
    ///   1..=100000)
    /// * `optInFastD_Period` — Smoothing period for %D (default 3, range 1..=100000)
    /// * `optInFastD_MAType` — MA type used to smooth %D (default 0 = SMA, values: 0=SMA, 1=EMA,
    ///   2=WMA, 3=DEMA, 4=TEMA, 5=TRIMA, 6=KAMA, 7=MAMA, 8=T3)
    /// * `outBegIdx` — Set to the input index of the first output value.
    /// * `outNBElement` — Set to the number of output values written.
    /// * `outFastK` — Unsmoothed stochastic of the RSI (raw %K)
    /// * `outFastD` — %K smoothed over FastD_Period (signal line)
    ///
    /// Integer parameters accept `i32::MIN` to select their default value.
    ///
    /// # Errors
    ///
    /// Returns [`RetCode::OutOfRangeStartIndex`] when `endIdx < startIdx`, and
    /// [`RetCode::BadParam`] when an optional parameter is outside its documented range.
    ///
    /// # Panics
    ///
    /// Input slices must cover `startIdx..=endIdx` and output slices must hold the number of values
    /// produced for that range: undersized slices panic or, for functions that forward to unchecked
    /// internals, cause undefined behavior. Sizing every output slice to the input length is always
    /// sufficient.
    ///
    /// # Examples
    ///
    /// ```
    /// use ta_lib::{Core, RetCode};
    ///
    /// let data: Vec<f64> = (0..252).map(|i| 100.0 + 10.0 * (0.1 * i as f64).sin()).collect();
    ///
    /// let core = Core::new();
    /// let mut out_beg = 0;
    /// let mut out_nb = 0;
    /// let mut fast_k = vec![0.0; 252];
    /// let mut fast_d = vec![0.0; 252];
    ///
    /// let ret = core.stochrsi(
    ///     0, data.len() - 1, &data, 14, 5, 3, 0,
    ///     &mut out_beg, &mut out_nb, &mut fast_k, &mut fast_d,
    /// );
    /// assert_eq!(ret, RetCode::Success);
    /// assert!(out_nb > 0);
    /// ```
    ///
    /// # See also
    ///
    /// [`Core::rsi`] · [`Core::stochf`] · [`Core::stoch`] · [`Core::ma`]
    ///
    /// # References
    ///
    /// * Tushar S. Chande, Stanley Kroll, *The New Technical Trader*, John Wiley & Sons (ISBN
    ///   0471597805)
    ///
    /// Further reading: [ta-lib.org/functions/stochrsi](https://ta-lib.org/functions/stochrsi/)
    #[doc(alias = "StochasticRSI")]
    pub fn stochrsi(
        &self,
        startIdx: usize,
        endIdx: usize,
        inReal: &[f64],
        mut optInTimePeriod: i32,
        mut optInFastK_Period: i32,
        mut optInFastD_Period: i32,
        mut optInFastD_MAType: i32,
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outFastK: &mut [f64],
        outFastD: &mut [f64],
    ) -> RetCode {
        if endIdx < startIdx {
            return RetCode::OutOfRangeStartIndex;
        }
        if ((optInTimePeriod) as i32) == (i32::MIN) {
            optInTimePeriod = 14;
        } else if (((optInTimePeriod) as i32) < 2) || (((optInTimePeriod) as i32) > 100000) {
            return RetCode::BadParam;
        }
        if ((optInFastK_Period) as i32) == (i32::MIN) {
            optInFastK_Period = 5;
        } else if (((optInFastK_Period) as i32) < 1) || (((optInFastK_Period) as i32) > 100000) {
            return RetCode::BadParam;
        }
        if ((optInFastD_Period) as i32) == (i32::MIN) {
            optInFastD_Period = 3;
        } else if (((optInFastD_Period) as i32) < 1) || (((optInFastD_Period) as i32) > 100000) {
            return RetCode::BadParam;
        }
        let mut startIdx = startIdx;
        let mut tempRSIBuffer: Vec<f64> = Vec::new();
        let mut retCode: RetCode = RetCode::Success;
        let mut lookbackTotal: usize = 0_usize;
        let mut lookbackSTOCHF: usize = 0_usize;
        let mut tempArraySize: usize = 0_usize;
        let mut outBegIdx1: usize = 0_usize;
        let mut outBegIdx2: usize = 0_usize;
        let mut outNbElement1: usize = 0_usize;
        // Stochastic RSI
        //
        // Reference: "Stochastic RSI and Dynamic Momentum Index"
        //            by Tushar Chande and Stanley Kroll
        //            Stock&Commodities V.11:5 (189-199)
        //
        // The TA-Lib version offer flexibility beyond what is explain
        // in the Stock&Commodities article.
        //
        // To calculate the "Unsmoothed stochastic RSI" with symetry like
        // explain in the article, keep the optInTimePeriod and optInFastK_Period
        // equal. Example:
        //
        //    unsmoothed stoch RSI 14 : optInTimePeriod   = 14
        //                              optInFastK_Period = 14
        //                              optInFastD_Period = 'x'
        //
        // The outFastK is the unsmoothed RSI discuss in the article.
        //
        // You can set the optInFastD_Period to smooth the RSI. The smooth
        // version will be found in outFastD. The outFastK will still contain
        // the unsmoothed stoch RSI. If you do not care about the smoothing of
        // the StochRSI, just leave optInFastD_Period to 1 and ignore outFastD.
        (*outBegIdx) = 0;
        (*outNBElement) = 0;
        // Adjust startIdx to account for the lookback period.
        lookbackSTOCHF = self.stochf_lookback(optInFastK_Period, optInFastD_Period, optInFastD_MAType);
        lookbackTotal = self.rsi_lookback(optInTimePeriod) + lookbackSTOCHF;
        if startIdx < lookbackTotal {
            startIdx = lookbackTotal;
        }
        // Make sure there is still something to evaluate.
        if startIdx > endIdx {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return RetCode::Success;
        }
        (*outBegIdx) = startIdx;
        tempArraySize = endIdx - startIdx + 1 + lookbackSTOCHF;
        tempRSIBuffer = vec![0.0_f64; (tempArraySize * 1) as usize];
        retCode = self.rsi_unguarded(startIdx - lookbackSTOCHF, endIdx, inReal, optInTimePeriod, &mut outBegIdx1, &mut outNbElement1, &mut tempRSIBuffer[..]);
        if retCode != RetCode::Success || outNbElement1 == 0 {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return retCode;
        }
        retCode = self.stochf_unguarded(0, tempArraySize - 1, &tempRSIBuffer, &tempRSIBuffer, &tempRSIBuffer, optInFastK_Period, optInFastD_Period, optInFastD_MAType, &mut outBegIdx2, outNBElement, outFastK, outFastD);
        if retCode != RetCode::Success || ((*outNBElement) as usize) == 0 {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return retCode;
        }
        return RetCode::Success;
    }
    /// Unchecked variant of [`Core::stochrsi`], used for internal cross-indicator calls.
    ///
    /// Skips parameter validation and uses unchecked indexing internally. Every argument must
    /// satisfy the constraints documented on [`Core::stochrsi`]; an out-of-range parameter, an
    /// input slice not covering `startIdx..=endIdx`, or an undersized output slice may panic or
    /// cause undefined behavior. Prefer [`Core::stochrsi`].
    #[inline]
    pub fn stochrsi_unguarded(
        &self,
        mut startIdx: usize,
        endIdx: usize,
        inReal: &[f64],
        mut optInTimePeriod: i32,
        mut optInFastK_Period: i32,
        mut optInFastD_Period: i32,
        mut optInFastD_MAType: i32,
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outFastK: &mut [f64],
        outFastD: &mut [f64],
    ) -> RetCode {
        let mut tempRSIBuffer: Vec<f64> = Vec::new();
        let mut retCode: RetCode = RetCode::Success;
        let mut lookbackTotal: usize = 0_usize;
        let mut lookbackSTOCHF: usize = 0_usize;
        let mut tempArraySize: usize = 0_usize;
        let mut outBegIdx1: usize = 0_usize;
        let mut outBegIdx2: usize = 0_usize;
        let mut outNbElement1: usize = 0_usize;
        unsafe {
        assert!(endIdx < inReal.len());
        let _assertLb = self.stochrsi_lookback(optInTimePeriod, optInFastK_Period, optInFastD_Period, optInFastD_MAType);
        let _assertStart = if startIdx > _assertLb { startIdx } else { _assertLb };
        assert!(_assertStart > endIdx || endIdx - _assertStart < outFastK.len());
        assert!(_assertStart > endIdx || endIdx - _assertStart < outFastD.len());
        (*outBegIdx) = 0;
        (*outNBElement) = 0;
        lookbackSTOCHF = self.stochf_lookback(optInFastK_Period, optInFastD_Period, optInFastD_MAType);
        lookbackTotal = self.rsi_lookback(optInTimePeriod) + lookbackSTOCHF;
        if startIdx < lookbackTotal {
            startIdx = lookbackTotal;
        }
        if startIdx > endIdx {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return RetCode::Success;
        }
        (*outBegIdx) = startIdx;
        tempArraySize = endIdx - startIdx + 1 + lookbackSTOCHF;
        tempRSIBuffer = vec![0.0_f64; (tempArraySize * 1) as usize];
        retCode = self.rsi_unguarded(startIdx - lookbackSTOCHF, endIdx, inReal, optInTimePeriod, &mut outBegIdx1, &mut outNbElement1, &mut tempRSIBuffer[..]);
        if retCode != RetCode::Success || outNbElement1 == 0 {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return retCode;
        }
        retCode = self.stochf_unguarded(0, tempArraySize - 1, &tempRSIBuffer, &tempRSIBuffer, &tempRSIBuffer, optInFastK_Period, optInFastD_Period, optInFastD_MAType, &mut outBegIdx2, outNBElement, outFastK, outFastD);
        if retCode != RetCode::Success || ((*outNBElement) as usize) == 0 {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return retCode;
        }
        return RetCode::Success;
        } // unsafe
    }
}
/***************/
/* End of File */
/***************/
