/* 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
 *  -------------------------------------------------------------------
 *  022005 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::cdlmathold`]: the number of leading input values consumed before
    /// the first output value can be produced.
    ///
    /// # Arguments
    ///
    /// * `optInPenetration` — Max fraction of the 1st white body the reaction days (3rd, 4th) may
    ///   penetrate; default 0.5 (default 0.5, minimum 0)
    ///
    /// Returns `usize::MAX` when a parameter is out of range. Integer parameters accept `i32::MIN`
    /// to select their default value.
    #[inline]
    pub fn cdlmathold_lookback(&self, mut optInPenetration: f64) -> usize {
        #[allow(non_snake_case)]
        let BodyLong_rangeType: i32 = self.candle_settings.body_long.range_type;
        #[allow(non_snake_case)]
        let BodyLong_avgPeriod: i32 = self.candle_settings.body_long.avg_period;
        #[allow(non_snake_case)]
        let BodyLong_factor: f64 = self.candle_settings.body_long.factor;
        #[allow(non_snake_case)]
        let BodyShort_rangeType: i32 = self.candle_settings.body_short.range_type;
        #[allow(non_snake_case)]
        let BodyShort_avgPeriod: i32 = self.candle_settings.body_short.avg_period;
        #[allow(non_snake_case)]
        let BodyShort_factor: f64 = self.candle_settings.body_short.factor;
        return ((BodyShort_avgPeriod).max(BodyLong_avgPeriod) + 4) as usize;
    }
    /// A five-candle bullish continuation pattern: a long white candle, an upside real-body-gapped
    /// small black candle, two more small falling candles that hold within the first body, and a
    /// final white candle closing above the reaction days' highs. Signals continuation of the prior
    /// uptrend. Hit = bullish continuation of the existing uptrend.
    ///
    /// # Notes
    ///
    /// * The colors of the third and fourth (reaction) candles are not checked, although they are
    ///   classically black.
    /// * The continuation reading assumes a prior uptrend, which is not verified.
    ///
    /// # 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.
    /// * `optInPenetration` — Max fraction of the 1st white body the reaction days (3rd, 4th) may
    ///   penetrate; default 0.5 (default 0.5, minimum 0)
    /// * `outBegIdx` — Set to the input index of the first output value.
    /// * `outNBElement` — Set to the number of output values written.
    /// * `outInteger` — +100 when the bullish Mat Hold is detected, 0 otherwise. Never emits
    ///   -100.
    ///
    /// # 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 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.cdlmathold(
    ///     0, open.len() - 1, &open, &high, &low, &close, 0.5,
    ///     &mut out_beg, &mut out_nb, &mut out,
    /// );
    /// assert_eq!(ret, RetCode::Success);
    /// assert!(out_nb > 0);
    /// ```
    ///
    /// # See also
    ///
    /// [`Core::cdlrisefall3methods`] · [`Core::cdlxsidegap3methods`]
    ///
    /// Further reading: [ta-lib.org/functions/cdlmathold](https://ta-lib.org/functions/cdlmathold/)
    #[doc(alias = "MatHold")]
    pub fn cdlmathold(
        &self,
        startIdx: usize,
        endIdx: usize,
        inOpen: &[f64],
        inHigh: &[f64],
        inLow: &[f64],
        inClose: &[f64],
        mut optInPenetration: f64,
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outInteger: &mut [i32],
    ) -> RetCode {
        if endIdx < startIdx {
            return RetCode::OutOfRangeStartIndex;
        }
        let mut startIdx = startIdx;
        let mut BodyPeriodTotal: [f64; 5 as usize] = [0.0_f64; 5 as usize];
        let mut i: usize = 0_usize;
        let mut outIdx: usize = 0_usize;
        let mut totIdx: usize = 0_usize;
        let mut BodyShortTrailingIdx: usize = 0_usize;
        let mut BodyLongTrailingIdx: usize = 0_usize;
        let mut lookbackTotal: usize = 0_usize;
        #[allow(non_snake_case)]
        let BodyLong_rangeType: i32 = self.candle_settings.body_long.range_type;
        #[allow(non_snake_case)]
        let BodyLong_avgPeriod: i32 = self.candle_settings.body_long.avg_period;
        #[allow(non_snake_case)]
        let BodyLong_factor: f64 = self.candle_settings.body_long.factor;
        #[allow(non_snake_case)]
        let BodyShort_rangeType: i32 = self.candle_settings.body_short.range_type;
        #[allow(non_snake_case)]
        let BodyShort_avgPeriod: i32 = self.candle_settings.body_short.avg_period;
        #[allow(non_snake_case)]
        let BodyShort_factor: f64 = self.candle_settings.body_short.factor;
        // Identify the minimum number of price bar needed
        // to calculate at least one output.
        lookbackTotal = self.cdlmathold_lookback(optInPenetration);
        // 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.
        BodyPeriodTotal[4] = 0.0;
        BodyPeriodTotal[3] = 0.0;
        BodyPeriodTotal[2] = 0.0;
        BodyPeriodTotal[1] = 0.0;
        BodyPeriodTotal[0] = 0.0;
        BodyShortTrailingIdx = startIdx - (BodyShort_avgPeriod) as usize;
        BodyLongTrailingIdx = startIdx - (BodyLong_avgPeriod) as usize;
        i = BodyShortTrailingIdx;
        while i < startIdx {
            let mut _candlerange_0: f64;
            match BodyShort_rangeType {
                0 => {
                    _candlerange_0 = (inClose[i - 3] - inOpen[i - 3]).abs();
                }
                1 => {
                    _candlerange_0 = inHigh[i - 3] - inLow[i - 3];
                }
                2 => {
                    _candlerange_0 = inHigh[i - 3] - inLow[i - 3] - (inClose[i - 3] - inOpen[i - 3]).abs();
                }
                _ => {
                    _candlerange_0 = 0.0;
                }
            }
            BodyPeriodTotal[3] = BodyPeriodTotal[3] + _candlerange_0;
            let mut _candlerange_1: f64;
            match BodyShort_rangeType {
                0 => {
                    _candlerange_1 = (inClose[i - 2] - inOpen[i - 2]).abs();
                }
                1 => {
                    _candlerange_1 = inHigh[i - 2] - inLow[i - 2];
                }
                2 => {
                    _candlerange_1 = inHigh[i - 2] - inLow[i - 2] - (inClose[i - 2] - inOpen[i - 2]).abs();
                }
                _ => {
                    _candlerange_1 = 0.0;
                }
            }
            BodyPeriodTotal[2] = BodyPeriodTotal[2] + _candlerange_1;
            let mut _candlerange_2: f64;
            match BodyShort_rangeType {
                0 => {
                    _candlerange_2 = (inClose[i - 1] - inOpen[i - 1]).abs();
                }
                1 => {
                    _candlerange_2 = inHigh[i - 1] - inLow[i - 1];
                }
                2 => {
                    _candlerange_2 = inHigh[i - 1] - inLow[i - 1] - (inClose[i - 1] - inOpen[i - 1]).abs();
                }
                _ => {
                    _candlerange_2 = 0.0;
                }
            }
            BodyPeriodTotal[1] = BodyPeriodTotal[1] + _candlerange_2;
            i += 1;
        }
        i = BodyLongTrailingIdx;
        while i < startIdx {
            let mut _candlerange_3: f64;
            match BodyLong_rangeType {
                0 => {
                    _candlerange_3 = (inClose[i - 4] - inOpen[i - 4]).abs();
                }
                1 => {
                    _candlerange_3 = inHigh[i - 4] - inLow[i - 4];
                }
                2 => {
                    _candlerange_3 = inHigh[i - 4] - inLow[i - 4] - (inClose[i - 4] - inOpen[i - 4]).abs();
                }
                _ => {
                    _candlerange_3 = 0.0;
                }
            }
            BodyPeriodTotal[4] = BodyPeriodTotal[4] + _candlerange_3;
            i += 1;
        }
        i = startIdx;
        // Proceed with the calculation for the requested range.
        // Must have:
        // - first candle: long white candle
        // - upside gap between the first and the second bodies
        // - second candle: small black candle
        // - third and fourth candles: falling small real body candlesticks (commonly black) that hold within the long
        //   white candle's body and are higher than the reaction days of the rising three methods
        // - fifth candle: white candle that opens above the previous small candle's close and closes higher than the
        //   high of the highest reaction day
        // The meaning of "short" and "long" is specified with TA_SetCandleSettings;
        // "hold within" means "a part of the real body must be within";
        // optInPenetration is the maximum percentage of the first white body the reaction days can penetrate (it is
        // to specify how much the reaction days should be "higher than the reaction days of the rising three methods")
        // outInteger is positive (1 to 100): mat hold is always bullish
        outIdx = 0;
        loop {
            if (if inClose[i - 4] >= inOpen[i - 4] { 1 } else { 0 - 1 }) == 1 &&       // white, black, 2 black or white, white
               ((if inClose[i - 3] >= inOpen[i - 3] { 1 } else { 0 - 1 })) as i32 == 0 - 1 &&
               (if inClose[i] >= inOpen[i] { 1 } else { 0 - 1 }) == 1 &&
               ((if (inOpen[i - 3]).min(inClose[i - 3]) > (inOpen[i - 4]).max(inClose[i - 4]) { 1 } else { 0 }) != 0) && // upside gap 1st to 2nd
               (inOpen[i - 2]).min(inClose[i - 2]) < inClose[i - 4] &&                 // 3rd to 4th hold within 1st: a part of the real body must be within 1st real body
               (inOpen[i - 1]).min(inClose[i - 1]) < inClose[i - 4] &&
               (inOpen[i - 2]).min(inClose[i - 2]) > inClose[i - 4] - (inClose[i - 4] - inOpen[i - 4]).abs() * optInPenetration && // reaction days penetrate first body less than optInPenetration percent
               (inOpen[i - 1]).min(inClose[i - 1]) > inClose[i - 4] - (inClose[i - 4] - inOpen[i - 4]).abs() * optInPenetration &&
               (inClose[i - 2]).max(inOpen[i - 2]) < inOpen[i - 3] &&                  // 2nd to 4th are falling
               (inClose[i - 1]).max(inOpen[i - 1]) < (inClose[i - 2]).max(inOpen[i - 2]) &&
               inOpen[i] > inClose[i - 1] &&                                           // 5th opens above the prior close
               inClose[i] > ((inHigh[i - 3]).max(inHigh[i - 2])).max(inHigh[i - 1]) && // 5th closes above the highest high of the reaction days
               (inClose[i - 4] - inOpen[i - 4]).abs() > ((BodyLong_factor) * (if (BodyLong_avgPeriod) != 0 { (BodyPeriodTotal[4]) / (BodyLong_avgPeriod as f64) } else { match BodyLong_rangeType { 0 => (inClose[i - 4] - inOpen[i - 4]).abs(), 1 => (inHigh[i - 4]) - (inLow[i - 4]), _ => (inHigh[i - 4]) - (inLow[i - 4]) - ((inClose[i - 4]) - (inOpen[i - 4])).abs() } }) / (if (BodyLong_rangeType) == 2 { 2.0 } else { 1.0 })) && // 1st long, then 3 small
               (inClose[i - 3] - inOpen[i - 3]).abs() < ((BodyShort_factor) * (if (BodyShort_avgPeriod) != 0 { (BodyPeriodTotal[3]) / (BodyShort_avgPeriod as f64) } else { match BodyShort_rangeType { 0 => (inClose[i - 3] - inOpen[i - 3]).abs(), 1 => (inHigh[i - 3]) - (inLow[i - 3]), _ => (inHigh[i - 3]) - (inLow[i - 3]) - ((inClose[i - 3]) - (inOpen[i - 3])).abs() } }) / (if (BodyShort_rangeType) == 2 { 2.0 } else { 1.0 })) &&
               (inClose[i - 2] - inOpen[i - 2]).abs() < ((BodyShort_factor) * (if (BodyShort_avgPeriod) != 0 { (BodyPeriodTotal[2]) / (BodyShort_avgPeriod as f64) } else { match BodyShort_rangeType { 0 => (inClose[i - 2] - inOpen[i - 2]).abs(), 1 => (inHigh[i - 2]) - (inLow[i - 2]), _ => (inHigh[i - 2]) - (inLow[i - 2]) - ((inClose[i - 2]) - (inOpen[i - 2])).abs() } }) / (if (BodyShort_rangeType) == 2 { 2.0 } else { 1.0 })) &&
               (inClose[i - 1] - inOpen[i - 1]).abs() < ((BodyShort_factor) * (if (BodyShort_avgPeriod) != 0 { (BodyPeriodTotal[1]) / (BodyShort_avgPeriod as f64) } else { match BodyShort_rangeType { 0 => (inClose[i - 1] - inOpen[i - 1]).abs(), 1 => (inHigh[i - 1]) - (inLow[i - 1]), _ => (inHigh[i - 1]) - (inLow[i - 1]) - ((inClose[i - 1]) - (inOpen[i - 1])).abs() } }) / (if (BodyShort_rangeType) == 2 { 2.0 } else { 1.0 }))
            {
                outInteger[outIdx] = 100;
                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)
            let mut _candlerange_4: f64;
            match BodyLong_rangeType {
                0 => {
                    _candlerange_4 = (inClose[i - 4] - inOpen[i - 4]).abs();
                }
                1 => {
                    _candlerange_4 = inHigh[i - 4] - inLow[i - 4];
                }
                2 => {
                    _candlerange_4 = inHigh[i - 4] - inLow[i - 4] - (inClose[i - 4] - inOpen[i - 4]).abs();
                }
                _ => {
                    _candlerange_4 = 0.0;
                }
            }
            let mut _candlerange_5: f64;
            match BodyLong_rangeType {
                0 => {
                    _candlerange_5 = (inClose[BodyLongTrailingIdx - 4] - inOpen[BodyLongTrailingIdx - 4]).abs();
                }
                1 => {
                    _candlerange_5 = inHigh[BodyLongTrailingIdx - 4] - inLow[BodyLongTrailingIdx - 4];
                }
                2 => {
                    _candlerange_5 = inHigh[BodyLongTrailingIdx - 4] - inLow[BodyLongTrailingIdx - 4] - (inClose[BodyLongTrailingIdx - 4] - inOpen[BodyLongTrailingIdx - 4]).abs();
                }
                _ => {
                    _candlerange_5 = 0.0;
                }
            }
            BodyPeriodTotal[4] = BodyPeriodTotal[4] + (_candlerange_4 - _candlerange_5);
            // for( totIdx = 3; totIdx >= 1; totIdx -= 1 )
            totIdx = 3;
            loop {
                let mut _candlerange_6: f64;
                match BodyShort_rangeType {
                    0 => {
                        _candlerange_6 = (inClose[i - totIdx] - inOpen[i - totIdx]).abs();
                    }
                    1 => {
                        _candlerange_6 = inHigh[i - totIdx] - inLow[i - totIdx];
                    }
                    2 => {
                        _candlerange_6 = inHigh[i - totIdx] - inLow[i - totIdx] - (inClose[i - totIdx] - inOpen[i - totIdx]).abs();
                    }
                    _ => {
                        _candlerange_6 = 0.0;
                    }
                }
                let mut _candlerange_7: f64;
                match BodyShort_rangeType {
                    0 => {
                        _candlerange_7 = (inClose[BodyShortTrailingIdx - totIdx] - inOpen[BodyShortTrailingIdx - totIdx]).abs();
                    }
                    1 => {
                        _candlerange_7 = inHigh[BodyShortTrailingIdx - totIdx] - inLow[BodyShortTrailingIdx - totIdx];
                    }
                    2 => {
                        _candlerange_7 = inHigh[BodyShortTrailingIdx - totIdx] - inLow[BodyShortTrailingIdx - totIdx] - (inClose[BodyShortTrailingIdx - totIdx] - inOpen[BodyShortTrailingIdx - totIdx]).abs();
                    }
                    _ => {
                        _candlerange_7 = 0.0;
                    }
                }
                BodyPeriodTotal[totIdx] = BodyPeriodTotal[totIdx] + (_candlerange_6 - _candlerange_7);
                if totIdx == 1 { break; }
                totIdx -= 1;
            }
            i += 1;
            BodyShortTrailingIdx += 1;
            BodyLongTrailingIdx += 1;
            if !(i <= endIdx) { break; }
        }
        // All done. Indicate the output limits and return.
        (*outNBElement) = outIdx;
        (*outBegIdx) = startIdx;
        return RetCode::Success;
    }
    /// Unchecked variant of [`Core::cdlmathold`], used for internal cross-indicator calls.
    ///
    /// Skips parameter validation and uses unchecked indexing internally. Every argument must
    /// satisfy the constraints documented on [`Core::cdlmathold`]; 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::cdlmathold`].
    #[inline]
    pub fn cdlmathold_unguarded(
        &self,
        mut startIdx: usize,
        endIdx: usize,
        inOpen: &[f64],
        inHigh: &[f64],
        inLow: &[f64],
        inClose: &[f64],
        mut optInPenetration: f64,
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outInteger: &mut [i32],
    ) -> RetCode {
        let mut BodyPeriodTotal: [f64; 5 as usize] = [0.0_f64; 5 as usize];
        let mut i: usize = 0_usize;
        let mut outIdx: usize = 0_usize;
        let mut totIdx: usize = 0_usize;
        let mut BodyShortTrailingIdx: usize = 0_usize;
        let mut BodyLongTrailingIdx: usize = 0_usize;
        let mut lookbackTotal: usize = 0_usize;
        #[allow(non_snake_case)]
        let BodyLong_rangeType: i32 = self.candle_settings.body_long.range_type;
        #[allow(non_snake_case)]
        let BodyLong_avgPeriod: i32 = self.candle_settings.body_long.avg_period;
        #[allow(non_snake_case)]
        let BodyLong_factor: f64 = self.candle_settings.body_long.factor;
        #[allow(non_snake_case)]
        let BodyShort_rangeType: i32 = self.candle_settings.body_short.range_type;
        #[allow(non_snake_case)]
        let BodyShort_avgPeriod: i32 = self.candle_settings.body_short.avg_period;
        #[allow(non_snake_case)]
        let BodyShort_factor: f64 = self.candle_settings.body_short.factor;
        unsafe {
        assert!(endIdx < inOpen.len());
        assert!(endIdx < inHigh.len());
        assert!(endIdx < inLow.len());
        assert!(endIdx < inClose.len());
        let _assertLb = self.cdlmathold_lookback(optInPenetration);
        let _assertStart = if startIdx > _assertLb { startIdx } else { _assertLb };
        assert!(_assertStart > endIdx || endIdx - _assertStart < outInteger.len());
        lookbackTotal = self.cdlmathold_lookback(optInPenetration);
        if startIdx < lookbackTotal {
            startIdx = lookbackTotal;
        }
        if startIdx > endIdx {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return RetCode::Success;
        }
        *BodyPeriodTotal.as_mut_ptr().add(4) = 0.0;
        *BodyPeriodTotal.as_mut_ptr().add(3) = 0.0;
        *BodyPeriodTotal.as_mut_ptr().add(2) = 0.0;
        *BodyPeriodTotal.as_mut_ptr().add(1) = 0.0;
        *BodyPeriodTotal.as_mut_ptr().add(0) = 0.0;
        BodyShortTrailingIdx = startIdx - (BodyShort_avgPeriod) as usize;
        BodyLongTrailingIdx = startIdx - (BodyLong_avgPeriod) as usize;
        i = BodyShortTrailingIdx;
        while i < startIdx {
            let mut _candlerange_0: f64;
            match BodyShort_rangeType {
                0 => {
                    _candlerange_0 = (*inClose.as_ptr().add(i - 3) - *inOpen.as_ptr().add(i - 3)).abs();
                }
                1 => {
                    _candlerange_0 = *inHigh.as_ptr().add(i - 3) - *inLow.as_ptr().add(i - 3);
                }
                2 => {
                    _candlerange_0 = *inHigh.as_ptr().add(i - 3) - *inLow.as_ptr().add(i - 3) - (*inClose.as_ptr().add(i - 3) - *inOpen.as_ptr().add(i - 3)).abs();
                }
                _ => {
                    _candlerange_0 = 0.0;
                }
            }
            *BodyPeriodTotal.as_mut_ptr().add(3) = *BodyPeriodTotal.as_ptr().add(3) + _candlerange_0;
            let mut _candlerange_1: f64;
            match BodyShort_rangeType {
                0 => {
                    _candlerange_1 = (*inClose.as_ptr().add(i - 2) - *inOpen.as_ptr().add(i - 2)).abs();
                }
                1 => {
                    _candlerange_1 = *inHigh.as_ptr().add(i - 2) - *inLow.as_ptr().add(i - 2);
                }
                2 => {
                    _candlerange_1 = *inHigh.as_ptr().add(i - 2) - *inLow.as_ptr().add(i - 2) - (*inClose.as_ptr().add(i - 2) - *inOpen.as_ptr().add(i - 2)).abs();
                }
                _ => {
                    _candlerange_1 = 0.0;
                }
            }
            *BodyPeriodTotal.as_mut_ptr().add(2) = *BodyPeriodTotal.as_ptr().add(2) + _candlerange_1;
            let mut _candlerange_2: f64;
            match BodyShort_rangeType {
                0 => {
                    _candlerange_2 = (*inClose.as_ptr().add(i - 1) - *inOpen.as_ptr().add(i - 1)).abs();
                }
                1 => {
                    _candlerange_2 = *inHigh.as_ptr().add(i - 1) - *inLow.as_ptr().add(i - 1);
                }
                2 => {
                    _candlerange_2 = *inHigh.as_ptr().add(i - 1) - *inLow.as_ptr().add(i - 1) - (*inClose.as_ptr().add(i - 1) - *inOpen.as_ptr().add(i - 1)).abs();
                }
                _ => {
                    _candlerange_2 = 0.0;
                }
            }
            *BodyPeriodTotal.as_mut_ptr().add(1) = *BodyPeriodTotal.as_ptr().add(1) + _candlerange_2;
            i += 1;
        }
        i = BodyLongTrailingIdx;
        while i < startIdx {
            let mut _candlerange_3: f64;
            match BodyLong_rangeType {
                0 => {
                    _candlerange_3 = (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs();
                }
                1 => {
                    _candlerange_3 = *inHigh.as_ptr().add(i - 4) - *inLow.as_ptr().add(i - 4);
                }
                2 => {
                    _candlerange_3 = *inHigh.as_ptr().add(i - 4) - *inLow.as_ptr().add(i - 4) - (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs();
                }
                _ => {
                    _candlerange_3 = 0.0;
                }
            }
            *BodyPeriodTotal.as_mut_ptr().add(4) = *BodyPeriodTotal.as_ptr().add(4) + _candlerange_3;
            i += 1;
        }
        i = startIdx;
        outIdx = 0;
        loop {
            if (if *inClose.as_ptr().add(i - 4) >= *inOpen.as_ptr().add(i - 4) { 1 } else { 0 - 1 }) == 1 && ((if *inClose.as_ptr().add(i - 3) >= *inOpen.as_ptr().add(i - 3) { 1 } else { 0 - 1 })) as i32 == 0 - 1 && (if *inClose.as_ptr().add(i) >= *inOpen.as_ptr().add(i) { 1 } else { 0 - 1 }) == 1 && ((if (*inOpen.as_ptr().add(i - 3)).min(*inClose.as_ptr().add(i - 3)) > (*inOpen.as_ptr().add(i - 4)).max(*inClose.as_ptr().add(i - 4)) { 1 } else { 0 }) != 0) && (*inOpen.as_ptr().add(i - 2)).min(*inClose.as_ptr().add(i - 2)) < *inClose.as_ptr().add(i - 4) && (*inOpen.as_ptr().add(i - 1)).min(*inClose.as_ptr().add(i - 1)) < *inClose.as_ptr().add(i - 4) && (*inOpen.as_ptr().add(i - 2)).min(*inClose.as_ptr().add(i - 2)) > *inClose.as_ptr().add(i - 4) - (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs() * optInPenetration && (*inOpen.as_ptr().add(i - 1)).min(*inClose.as_ptr().add(i - 1)) > *inClose.as_ptr().add(i - 4) - (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs() * optInPenetration && (*inClose.as_ptr().add(i - 2)).max(*inOpen.as_ptr().add(i - 2)) < *inOpen.as_ptr().add(i - 3) && (*inClose.as_ptr().add(i - 1)).max(*inOpen.as_ptr().add(i - 1)) < (*inClose.as_ptr().add(i - 2)).max(*inOpen.as_ptr().add(i - 2)) && *inOpen.as_ptr().add(i) > *inClose.as_ptr().add(i - 1) && *inClose.as_ptr().add(i) > ((*inHigh.as_ptr().add(i - 3)).max(*inHigh.as_ptr().add(i - 2))).max(*inHigh.as_ptr().add(i - 1)) && (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs() > ((BodyLong_factor) * (if (BodyLong_avgPeriod) != 0 { (*BodyPeriodTotal.as_ptr().add(4)) / (BodyLong_avgPeriod as f64) } else { match BodyLong_rangeType { 0 => (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs(), 1 => (*inHigh.as_ptr().add(i - 4)) - (*inLow.as_ptr().add(i - 4)), _ => (*inHigh.as_ptr().add(i - 4)) - (*inLow.as_ptr().add(i - 4)) - ((*inClose.as_ptr().add(i - 4)) - (*inOpen.as_ptr().add(i - 4))).abs() } }) / (if (BodyLong_rangeType) == 2 { 2.0 } else { 1.0 })) && (*inClose.as_ptr().add(i - 3) - *inOpen.as_ptr().add(i - 3)).abs() < ((BodyShort_factor) * (if (BodyShort_avgPeriod) != 0 { (*BodyPeriodTotal.as_ptr().add(3)) / (BodyShort_avgPeriod as f64) } else { match BodyShort_rangeType { 0 => (*inClose.as_ptr().add(i - 3) - *inOpen.as_ptr().add(i - 3)).abs(), 1 => (*inHigh.as_ptr().add(i - 3)) - (*inLow.as_ptr().add(i - 3)), _ => (*inHigh.as_ptr().add(i - 3)) - (*inLow.as_ptr().add(i - 3)) - ((*inClose.as_ptr().add(i - 3)) - (*inOpen.as_ptr().add(i - 3))).abs() } }) / (if (BodyShort_rangeType) == 2 { 2.0 } else { 1.0 })) && (*inClose.as_ptr().add(i - 2) - *inOpen.as_ptr().add(i - 2)).abs() < ((BodyShort_factor) * (if (BodyShort_avgPeriod) != 0 { (*BodyPeriodTotal.as_ptr().add(2)) / (BodyShort_avgPeriod as f64) } else { match BodyShort_rangeType { 0 => (*inClose.as_ptr().add(i - 2) - *inOpen.as_ptr().add(i - 2)).abs(), 1 => (*inHigh.as_ptr().add(i - 2)) - (*inLow.as_ptr().add(i - 2)), _ => (*inHigh.as_ptr().add(i - 2)) - (*inLow.as_ptr().add(i - 2)) - ((*inClose.as_ptr().add(i - 2)) - (*inOpen.as_ptr().add(i - 2))).abs() } }) / (if (BodyShort_rangeType) == 2 { 2.0 } else { 1.0 })) && (*inClose.as_ptr().add(i - 1) - *inOpen.as_ptr().add(i - 1)).abs() < ((BodyShort_factor) * (if (BodyShort_avgPeriod) != 0 { (*BodyPeriodTotal.as_ptr().add(1)) / (BodyShort_avgPeriod as f64) } else { match BodyShort_rangeType { 0 => (*inClose.as_ptr().add(i - 1) - *inOpen.as_ptr().add(i - 1)).abs(), 1 => (*inHigh.as_ptr().add(i - 1)) - (*inLow.as_ptr().add(i - 1)), _ => (*inHigh.as_ptr().add(i - 1)) - (*inLow.as_ptr().add(i - 1)) - ((*inClose.as_ptr().add(i - 1)) - (*inOpen.as_ptr().add(i - 1))).abs() } }) / (if (BodyShort_rangeType) == 2 { 2.0 } else { 1.0 })) {
                *outInteger.as_mut_ptr().add(outIdx) = 100;
                outIdx += 1;
            } else {
                *outInteger.as_mut_ptr().add(outIdx) = 0;
                outIdx += 1;
            }
            let mut _candlerange_4: f64;
            match BodyLong_rangeType {
                0 => {
                    _candlerange_4 = (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs();
                }
                1 => {
                    _candlerange_4 = *inHigh.as_ptr().add(i - 4) - *inLow.as_ptr().add(i - 4);
                }
                2 => {
                    _candlerange_4 = *inHigh.as_ptr().add(i - 4) - *inLow.as_ptr().add(i - 4) - (*inClose.as_ptr().add(i - 4) - *inOpen.as_ptr().add(i - 4)).abs();
                }
                _ => {
                    _candlerange_4 = 0.0;
                }
            }
            let mut _candlerange_5: f64;
            match BodyLong_rangeType {
                0 => {
                    _candlerange_5 = (*inClose.as_ptr().add(BodyLongTrailingIdx - 4) - *inOpen.as_ptr().add(BodyLongTrailingIdx - 4)).abs();
                }
                1 => {
                    _candlerange_5 = *inHigh.as_ptr().add(BodyLongTrailingIdx - 4) - *inLow.as_ptr().add(BodyLongTrailingIdx - 4);
                }
                2 => {
                    _candlerange_5 = *inHigh.as_ptr().add(BodyLongTrailingIdx - 4) - *inLow.as_ptr().add(BodyLongTrailingIdx - 4) - (*inClose.as_ptr().add(BodyLongTrailingIdx - 4) - *inOpen.as_ptr().add(BodyLongTrailingIdx - 4)).abs();
                }
                _ => {
                    _candlerange_5 = 0.0;
                }
            }
            *BodyPeriodTotal.as_mut_ptr().add(4) = *BodyPeriodTotal.as_ptr().add(4) + (_candlerange_4 - _candlerange_5);
            // for( totIdx = 3; totIdx >= 1; totIdx -= 1 )
            totIdx = 3;
            loop {
                let mut _candlerange_6: f64;
                match BodyShort_rangeType {
                    0 => {
                        _candlerange_6 = (*inClose.as_ptr().add(i - totIdx) - *inOpen.as_ptr().add(i - totIdx)).abs();
                    }
                    1 => {
                        _candlerange_6 = *inHigh.as_ptr().add(i - totIdx) - *inLow.as_ptr().add(i - totIdx);
                    }
                    2 => {
                        _candlerange_6 = *inHigh.as_ptr().add(i - totIdx) - *inLow.as_ptr().add(i - totIdx) - (*inClose.as_ptr().add(i - totIdx) - *inOpen.as_ptr().add(i - totIdx)).abs();
                    }
                    _ => {
                        _candlerange_6 = 0.0;
                    }
                }
                let mut _candlerange_7: f64;
                match BodyShort_rangeType {
                    0 => {
                        _candlerange_7 = (*inClose.as_ptr().add(BodyShortTrailingIdx - totIdx) - *inOpen.as_ptr().add(BodyShortTrailingIdx - totIdx)).abs();
                    }
                    1 => {
                        _candlerange_7 = *inHigh.as_ptr().add(BodyShortTrailingIdx - totIdx) - *inLow.as_ptr().add(BodyShortTrailingIdx - totIdx);
                    }
                    2 => {
                        _candlerange_7 = *inHigh.as_ptr().add(BodyShortTrailingIdx - totIdx) - *inLow.as_ptr().add(BodyShortTrailingIdx - totIdx) - (*inClose.as_ptr().add(BodyShortTrailingIdx - totIdx) - *inOpen.as_ptr().add(BodyShortTrailingIdx - totIdx)).abs();
                    }
                    _ => {
                        _candlerange_7 = 0.0;
                    }
                }
                *BodyPeriodTotal.as_mut_ptr().add(totIdx) = *BodyPeriodTotal.as_ptr().add(totIdx) + (_candlerange_6 - _candlerange_7);
                if totIdx == 1 { break; }
                totIdx -= 1;
            }
            i += 1;
            BodyShortTrailingIdx += 1;
            BodyLongTrailingIdx += 1;
            if !(i <= endIdx) { break; }
        }
        (*outNBElement) = outIdx;
        (*outBegIdx) = startIdx;
        return RetCode::Success;
        } // unsafe
    }
}
/***************/
/* End of File */
/***************/
