/* 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
 *  -------------------------------------------------------------------
 *  AC       Angelo Ciceri
 *
 *
 * Change history:
 *
 *  MMDDYY BY   Description
 *  -------------------------------------------------------------------
 *  011605 AC   Creation
 */

// 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::cdlxsidegap3methods`]: the number of leading input values
    /// consumed before the first output value can be produced.
    pub fn cdlxsidegap3methods_lookback(&self) -> usize {
        return (2) as usize;
    }
    /// A three-candle continuation pattern: two same-color candles separated by a real-body gap,
    /// followed by an opposite-color candle that fills into the gap. Bullish (upside) when the
    /// first two candles are white, bearish (downside) when they are black. A hit signals trend
    /// continuation: +100 bullish (uptrend resumes), -100 bearish (downtrend resumes).
    ///
    /// # Notes
    ///
    /// * This continuation pattern does not verify the prior trend it classically assumes; the
    ///   caller must confirm the trend.
    ///
    /// # Arguments
    ///
    /// * `startIdx` — Start index of the requested calculation range.
    /// * `endIdx` — End index of the requested calculation range (inclusive).
    /// * `inOpen` — Open prices per bar.
    /// * `inHigh` — High prices per bar.
    /// * `inLow` — Low prices per bar.
    /// * `inClose` — Close prices per bar.
    /// * `outBegIdx` — Set to the input index of the first output value.
    /// * `outNBElement` — Set to the number of output values written.
    /// * `outInteger` — +100 when the two same-color candles are white (bullish/upside
    ///   continuation), -100 when black (bearish/downside continuation), 0 otherwise. Equals
    ///   candlecolor(1st candle) * 100.
    ///
    /// # Errors
    ///
    /// Returns [`RetCode::OutOfRangeStartIndex`] when `endIdx < startIdx`.
    ///
    /// # 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 open: Vec<f64> = (0..252).map(|i| 100.0 + 10.0 * (0.1 * i as f64 - 0.05).sin()).collect();
    /// let high: Vec<f64> = (0..252).map(|i| 101.0 + 10.0 * (0.1 * i as f64).sin()).collect();
    /// let low: Vec<f64> = (0..252).map(|i| 99.0 + 10.0 * (0.1 * i as f64).sin()).collect();
    /// let close: 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 out = vec![0i32; 252];
    ///
    /// let ret = core.cdlxsidegap3methods(
    ///     0, open.len() - 1, &open, &high, &low, &close,
    ///     &mut out_beg, &mut out_nb, &mut out,
    /// );
    /// assert_eq!(ret, RetCode::Success);
    /// assert!(out_nb > 0);
    /// ```
    ///
    /// # See also
    ///
    /// [`Core::cdlgapsidesidewhite`] · [`Core::cdltasukigap`] · [`Core::cdlrisefall3methods`]
    ///
    /// Further reading:
    /// [ta-lib.org/functions/cdlxsidegap3methods](https://ta-lib.org/functions/cdlxsidegap3methods/)
    #[doc(alias = "UpsideDownsideGapThreeMethods")]
    #[doc(alias = "UpsideGapThreeMethods")]
    #[doc(alias = "DownsideGapThreeMethods")]
    pub fn cdlxsidegap3methods(
        &self,
        startIdx: usize,
        endIdx: usize,
        inOpen: &[f64],
        inHigh: &[f64],
        inLow: &[f64],
        inClose: &[f64],
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outInteger: &mut [i32],
    ) -> RetCode {
        if endIdx < startIdx {
            return RetCode::OutOfRangeStartIndex;
        }
        let mut startIdx = startIdx;
        let mut i: usize = 0_usize;
        let mut outIdx: usize = 0_usize;
        let mut lookbackTotal: usize = 0_usize;
        // Identify the minimum number of price bar needed
        // to calculate at least one output.
        lookbackTotal = self.cdlxsidegap3methods_lookback();
        // Move up the start index if there is not
        // enough initial data.
        if startIdx < lookbackTotal {
            startIdx = lookbackTotal;
        }
        // Make sure there is still something to evaluate.
        if startIdx > endIdx {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return RetCode::Success;
        }
        // Do the calculation using tight loops.
        // Add-up the initial period, except for the last value.
        i = startIdx;
        // Proceed with the calculation for the requested range.
        // Must have:
        // - first candle: white (black) candle
        // - second candle: white (black) candle
        // - upside (downside) gap between the first and the second real bodies
        // - third candle: black (white) candle that opens within the second real body and closes within the first real body
        // outInteger is positive (1 to 100) when bullish or negative (-1 to -100) when bearish;
        // the user should consider that up/downside gap 3 methods is significant when it appears in a trend, while this
        // function does not consider it
        outIdx = 0;
        loop {
            if (if inClose[i - 2] >= inOpen[i - 2] { 1 } else { 0 - 1 }) == (if inClose[i - 1] >= inOpen[i - 1] { 1 } else { 0 - 1 }) && // 1st and 2nd of same color
               (if inClose[i - 1] >= inOpen[i - 1] { 1 } else { 0 - 1 }) == 0 - (if inClose[i] >= inOpen[i] { 1 } else { 0 - 1 }) && // 3rd opposite color
               inOpen[i] < (inClose[i - 1]).max(inOpen[i - 1]) &&  // 3rd opens within 2nd rb
               inOpen[i] > (inClose[i - 1]).min(inOpen[i - 1]) &&
               inClose[i] < (inClose[i - 2]).max(inOpen[i - 2]) && // 3rd closes within 1st rb
               inClose[i] > (inClose[i - 2]).min(inOpen[i - 2]) &&
               ((if inClose[i - 2] >= inOpen[i - 2] { 1 } else { 0 - 1 }) == 1 && ((if (inOpen[i - 1]).min(inClose[i - 1]) > (inOpen[i - 2]).max(inClose[i - 2]) { 1 } else { 0 }) != 0) || ((if inClose[i - 2] >= inOpen[i - 2] { 1 } else { 0 - 1 })) as i32 == 0 - 1 && ((if (inOpen[i - 1]).max(inClose[i - 1]) < (inOpen[i - 2]).min(inClose[i - 2]) { 1 } else { 0 }) != 0)) // when 1st is white upside gap when 1st is black downside gap
            {
                outInteger[outIdx] = ((if inClose[i - 2] >= inOpen[i - 2] { 1 } else { 0 - 1 }) * 100) as i32;
                outIdx += 1;
            } else {
                outInteger[outIdx] = 0;
                outIdx += 1;
            }
            // add the current range and subtract the first range: this is done after the pattern recognition
            // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
            i += 1;
            if !(i <= endIdx) { break; }
        }
        // All done. Indicate the output limits and return.
        (*outNBElement) = outIdx;
        (*outBegIdx) = startIdx;
        return RetCode::Success;
    }
    /// Unchecked variant of [`Core::cdlxsidegap3methods`], used for internal cross-indicator calls.
    ///
    /// Skips parameter validation and uses unchecked indexing internally. Every argument must
    /// satisfy the constraints documented on [`Core::cdlxsidegap3methods`]; 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::cdlxsidegap3methods`].
    #[inline]
    pub fn cdlxsidegap3methods_unguarded(
        &self,
        mut startIdx: usize,
        endIdx: usize,
        inOpen: &[f64],
        inHigh: &[f64],
        inLow: &[f64],
        inClose: &[f64],
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outInteger: &mut [i32],
    ) -> RetCode {
        let mut i: usize = 0_usize;
        let mut outIdx: usize = 0_usize;
        let mut lookbackTotal: usize = 0_usize;
        unsafe {
        assert!(endIdx < inOpen.len());
        assert!(endIdx < inHigh.len());
        assert!(endIdx < inLow.len());
        assert!(endIdx < inClose.len());
        let _assertLb = self.cdlxsidegap3methods_lookback();
        let _assertStart = if startIdx > _assertLb { startIdx } else { _assertLb };
        assert!(_assertStart > endIdx || endIdx - _assertStart < outInteger.len());
        lookbackTotal = self.cdlxsidegap3methods_lookback();
        if startIdx < lookbackTotal {
            startIdx = lookbackTotal;
        }
        if startIdx > endIdx {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return RetCode::Success;
        }
        i = startIdx;
        outIdx = 0;
        loop {
            if (if *inClose.as_ptr().add(i - 2) >= *inOpen.as_ptr().add(i - 2) { 1 } else { 0 - 1 }) == (if *inClose.as_ptr().add(i - 1) >= *inOpen.as_ptr().add(i - 1) { 1 } else { 0 - 1 }) && (if *inClose.as_ptr().add(i - 1) >= *inOpen.as_ptr().add(i - 1) { 1 } else { 0 - 1 }) == 0 - (if *inClose.as_ptr().add(i) >= *inOpen.as_ptr().add(i) { 1 } else { 0 - 1 }) && *inOpen.as_ptr().add(i) < (*inClose.as_ptr().add(i - 1)).max(*inOpen.as_ptr().add(i - 1)) && *inOpen.as_ptr().add(i) > (*inClose.as_ptr().add(i - 1)).min(*inOpen.as_ptr().add(i - 1)) && *inClose.as_ptr().add(i) < (*inClose.as_ptr().add(i - 2)).max(*inOpen.as_ptr().add(i - 2)) && *inClose.as_ptr().add(i) > (*inClose.as_ptr().add(i - 2)).min(*inOpen.as_ptr().add(i - 2)) && ((if *inClose.as_ptr().add(i - 2) >= *inOpen.as_ptr().add(i - 2) { 1 } else { 0 - 1 }) == 1 && ((if (*inOpen.as_ptr().add(i - 1)).min(*inClose.as_ptr().add(i - 1)) > (*inOpen.as_ptr().add(i - 2)).max(*inClose.as_ptr().add(i - 2)) { 1 } else { 0 }) != 0) || ((if *inClose.as_ptr().add(i - 2) >= *inOpen.as_ptr().add(i - 2) { 1 } else { 0 - 1 })) as i32 == 0 - 1 && ((if (*inOpen.as_ptr().add(i - 1)).max(*inClose.as_ptr().add(i - 1)) < (*inOpen.as_ptr().add(i - 2)).min(*inClose.as_ptr().add(i - 2)) { 1 } else { 0 }) != 0)) {
                *outInteger.as_mut_ptr().add(outIdx) = ((if *inClose.as_ptr().add(i - 2) >= *inOpen.as_ptr().add(i - 2) { 1 } else { 0 - 1 }) * 100) as i32;
                outIdx += 1;
            } else {
                *outInteger.as_mut_ptr().add(outIdx) = 0;
                outIdx += 1;
            }
            i += 1;
            if !(i <= endIdx) { break; }
        }
        (*outNBElement) = outIdx;
        (*outBegIdx) = startIdx;
        return RetCode::Success;
        } // unsafe
    }
}
/***************/
/* End of File */
/***************/
