/* 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
 *
 *
 * Change history:
 *
 *  MMDDYY BY   Description
 *  -------------------------------------------------------------------
 *  120802 MF   Template creation.
 *  052603 MF   Adapt code to compile with .NET Managed C++
 */

// 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::ht_dcphase`]: the number of leading input values consumed before
    /// the first output value can be produced.
    pub fn ht_dcphase_lookback(&self) -> usize {
        // 31 input are skip
        // +32 output are skip to account for misc lookback
        // ---
        //  63 Total Lookback
        //
        // 31 is for being compatible with Tradestation.
        // See mama_lookback for an explanation of the "32".
        return (63 + self.unstable_period[FuncUnstId::HtDcPhase as usize]) as usize;
    }
    /// Hilbert Transform Dominant Cycle Phase: the instantaneous phase (in degrees) of the dominant
    /// market cycle, derived from a homodyne discriminator on a Hilbert-transformed, smoothed
    /// price. One real output per bar. Output is degrees, wrapped so it never exceeds 315 (can go
    /// negative).
    ///
    /// # Arguments
    ///
    /// * `startIdx` — Start index of the requested calculation range.
    /// * `endIdx` — End index of the requested calculation range (inclusive).
    /// * `inReal` — Price series to analyze.
    /// * `outBegIdx` — Set to the input index of the first output value.
    /// * `outNBElement` — Set to the number of output values written.
    /// * `outReal` — Dominant cycle phase in degrees.
    ///
    /// # 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 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 out = vec![0.0; 252];
    ///
    /// let ret = core.ht_dcphase(0, data.len() - 1, &data, &mut out_beg, &mut out_nb, &mut out);
    /// assert_eq!(ret, RetCode::Success);
    /// assert!(out_nb > 0);
    /// ```
    ///
    /// # See also
    ///
    /// [`Core::ht_dcperiod`] · [`Core::ht_phasor`] · [`Core::ht_sine`] · [`Core::ht_trendline`]
    /// · [`Core::ht_trendmode`] · [`Core::mama`] · [`Core::wma`]
    ///
    /// # References
    ///
    /// * John F. Ehlers, *Rocket Science for Traders: Digital Signal Processing Applications*, John
    ///   Wiley & Sons (ISBN 0471405671)
    ///
    /// Further reading: [ta-lib.org/functions/ht_dcphase](https://ta-lib.org/functions/ht_dcphase/)
    #[doc(alias = "HilbertTransformDominantCyclePhase")]
    pub fn ht_dcphase(
        &self,
        startIdx: usize,
        endIdx: usize,
        inReal: &[f64],
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outReal: &mut [f64],
    ) -> RetCode {
        if endIdx < startIdx {
            return RetCode::OutOfRangeStartIndex;
        }
        let mut startIdx = startIdx;
        let mut outIdx: usize = 0_usize;
        let mut i: usize = 0_usize;
        let mut lookbackTotal: usize = 0_usize;
        let mut today: usize = 0_usize;
        let mut tempReal: f64 = 0.0_f64;
        let mut tempReal2: f64 = 0.0_f64;
        let mut adjustedPrevPeriod: f64 = 0.0_f64;
        let mut period: f64 = 0.0_f64;
        let mut trailingWMAIdx: usize = 0_usize;
        let mut periodWMASum: f64 = 0.0_f64;
        let mut periodWMASub: f64 = 0.0_f64;
        let mut trailingWMAValue: f64 = 0.0_f64;
        let mut smoothedValue: f64 = 0.0_f64;
        let mut a: f64 = 0.0_f64;
        let mut b: f64 = 0.0_f64;
        let mut hilbertTempReal: f64 = 0.0_f64;
        let mut hilbertIdx: usize = 0_usize;
        let mut detrender_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut detrender_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut detrender: f64 = 0.0_f64;
        let mut prev_detrender_Odd: f64 = 0.0_f64;
        let mut prev_detrender_Even: f64 = 0.0_f64;
        let mut prev_detrender_input_Odd: f64 = 0.0_f64;
        let mut prev_detrender_input_Even: f64 = 0.0_f64;
        let mut Q1_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut Q1_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut Q1: f64 = 0.0_f64;
        let mut prev_Q1_Odd: f64 = 0.0_f64;
        let mut prev_Q1_Even: f64 = 0.0_f64;
        let mut prev_Q1_input_Odd: f64 = 0.0_f64;
        let mut prev_Q1_input_Even: f64 = 0.0_f64;
        let mut jI_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jI_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jI: f64 = 0.0_f64;
        let mut prev_jI_Odd: f64 = 0.0_f64;
        let mut prev_jI_Even: f64 = 0.0_f64;
        let mut prev_jI_input_Odd: f64 = 0.0_f64;
        let mut prev_jI_input_Even: f64 = 0.0_f64;
        let mut jQ_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jQ_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jQ: f64 = 0.0_f64;
        let mut prev_jQ_Odd: f64 = 0.0_f64;
        let mut prev_jQ_Even: f64 = 0.0_f64;
        let mut prev_jQ_input_Odd: f64 = 0.0_f64;
        let mut prev_jQ_input_Even: f64 = 0.0_f64;
        let mut Q2: f64 = 0.0_f64;
        let mut I2: f64 = 0.0_f64;
        let mut prevQ2: f64 = 0.0_f64;
        let mut prevI2: f64 = 0.0_f64;
        let mut Re: f64 = 0.0_f64;
        let mut Im: f64 = 0.0_f64;
        let mut I1ForOddPrev2: f64 = 0.0_f64;
        let mut I1ForOddPrev3: f64 = 0.0_f64;
        let mut I1ForEvenPrev2: f64 = 0.0_f64;
        let mut I1ForEvenPrev3: f64 = 0.0_f64;
        let mut rad2Deg: f64 = 0.0_f64;
        let mut constDeg2RadBy360: f64 = 0.0_f64;
        let mut todayValue: f64 = 0.0_f64;
        let mut smoothPeriod: f64 = 0.0_f64;
        let mut smoothPrice: Vec<f64> = Vec::new();
        let mut smoothPrice_Idx: usize = 0;
        let mut maxIdx_smoothPrice: usize = 49;
        let mut idx: usize = 0_usize;
        let mut DCPeriodInt: usize = 0_usize;
        let mut DCPhase: f64 = 0.0_f64;
        let mut DCPeriod: f64 = 0.0_f64;
        let mut imagPart: f64 = 0.0_f64;
        let mut realPart: f64 = 0.0_f64;
        a = 0.0962;
        b = 0.5769;
        // Variable used for the price smoother (a weighted moving average).
        // Variables used for the Hilbert Transormation
        // Varaible used to keep track of the previous
        // smooth price. In the case of this algorithm,
        // we will never need more than 50 values.
        smoothPrice = vec![0.0_f64; maxIdx_smoothPrice + 1];
        smoothPrice_Idx = 0;
        // Variable used to calculate the dominant cycle phase
        // circular buffer already declared
        // Constant
        tempReal = (1_f64).atan();
        rad2Deg = 45.0 / tempReal;
        constDeg2RadBy360 = tempReal * 8.0;
        // Identify the minimum number of price bar needed
        // to calculate at least one output.
        lookbackTotal = (63 + self.unstable_period[FuncUnstId::HtDcPhase as usize]) as usize;
        // 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;
        }
        (*outBegIdx) = startIdx;
        // Initialize the price smoother, which is simply a weighted
        // moving average of the price.
        // To understand this algorithm, I strongly suggest to understand
        // first how TA_WMA is done.
        trailingWMAIdx = startIdx - lookbackTotal;
        today = trailingWMAIdx;
        // Initialization is same as WMA, except loop is unrolled
        // for speed optimization.
        tempReal = inReal[{ let _v = today; today += 1; _v }];
        periodWMASub = tempReal;
        periodWMASum = tempReal;
        tempReal = inReal[{ let _v = today; today += 1; _v }];
        periodWMASub += tempReal;
        periodWMASum += tempReal * 2.0;
        tempReal = inReal[{ let _v = today; today += 1; _v }];
        periodWMASub += tempReal;
        periodWMASum += tempReal * 3.0;
        trailingWMAValue = 0.0;
        // Subsequent WMA value are evaluated by using
        // the DO_PRICE_WMA macro.
        i = 34;
        loop {
            tempReal = inReal[{ let _v = today; today += 1; _v }];
            periodWMASub += tempReal;
            periodWMASub -= trailingWMAValue;
            periodWMASum += tempReal * 4.0;
            trailingWMAValue = inReal[{ let _v = trailingWMAIdx; trailingWMAIdx += 1; _v }];
            smoothedValue = periodWMASum * 0.1;
            periodWMASum -= periodWMASub;
            if !({ i = i.wrapping_sub(1); i } != 0) { break; }
        }
        // Initialize the circular buffers used by the hilbert
        // transform logic.
        // A buffer is used for odd day and another for even days.
        // This minimize the number of memory access and floating point
        // operations needed (note also that by using static circular buffer,
        // no large dynamic memory allocation is needed for storing
        // intermediate calculation!).
        hilbertIdx = 0;
        detrender_Odd[0] = 0.0;
        detrender_Odd[1] = 0.0;
        detrender_Odd[2] = 0.0;
        detrender_Even[0] = 0.0;
        detrender_Even[1] = 0.0;
        detrender_Even[2] = 0.0;
        detrender = 0.0;
        prev_detrender_Odd = 0.0;
        prev_detrender_Even = 0.0;
        prev_detrender_input_Odd = 0.0;
        prev_detrender_input_Even = 0.0;
        Q1_Odd[0] = 0.0;
        Q1_Odd[1] = 0.0;
        Q1_Odd[2] = 0.0;
        Q1_Even[0] = 0.0;
        Q1_Even[1] = 0.0;
        Q1_Even[2] = 0.0;
        Q1 = 0.0;
        prev_Q1_Odd = 0.0;
        prev_Q1_Even = 0.0;
        prev_Q1_input_Odd = 0.0;
        prev_Q1_input_Even = 0.0;
        jI_Odd[0] = 0.0;
        jI_Odd[1] = 0.0;
        jI_Odd[2] = 0.0;
        jI_Even[0] = 0.0;
        jI_Even[1] = 0.0;
        jI_Even[2] = 0.0;
        jI = 0.0;
        prev_jI_Odd = 0.0;
        prev_jI_Even = 0.0;
        prev_jI_input_Odd = 0.0;
        prev_jI_input_Even = 0.0;
        jQ_Odd[0] = 0.0;
        jQ_Odd[1] = 0.0;
        jQ_Odd[2] = 0.0;
        jQ_Even[0] = 0.0;
        jQ_Even[1] = 0.0;
        jQ_Even[2] = 0.0;
        jQ = 0.0;
        prev_jQ_Odd = 0.0;
        prev_jQ_Even = 0.0;
        prev_jQ_input_Odd = 0.0;
        prev_jQ_input_Even = 0.0;
        period = 0.0;
        outIdx = 0;
        prevQ2 = 0.0;
        prevI2 = prevQ2;
        Im = 0.0;
        Re = Im;
        I1ForEvenPrev3 = 0.0;
        I1ForOddPrev3 = I1ForEvenPrev3;
        I1ForEvenPrev2 = 0.0;
        I1ForOddPrev2 = I1ForEvenPrev2;
        smoothPeriod = 0.0;
        // for( i = 0; i < 50; i += 1 )
        i = 0;
        while i < 50 {
            smoothPrice[i] = 0.0;
            i += 1;
        }
        // The code is speed optimized and is most likely very
        // hard to follow if you do not already know well the
        // original algorithm.
        // To understadn better, it is strongly suggested to look
        // first at the Excel implementation in "test_MAMA.xls" included
        // in this package.
        DCPhase = 0.0;
        while today <= endIdx {
            adjustedPrevPeriod = (0.075 as f64).mul_add(period, 0.54);
            todayValue = inReal[today];
            periodWMASub += todayValue;
            periodWMASub -= trailingWMAValue;
            periodWMASum += todayValue * 4.0;
            trailingWMAValue = inReal[{ let _v = trailingWMAIdx; trailingWMAIdx += 1; _v }];
            smoothedValue = periodWMASum * 0.1;
            periodWMASum -= periodWMASub;
            // Remember the smoothedValue into the smoothPrice
            // circular buffer.
            smoothPrice[smoothPrice_Idx] = smoothedValue;
            if today % 2 == 0 {
                // Do the Hilbert Transforms for even price bar
                hilbertTempReal = a * smoothedValue;
                detrender = 0_f64 - detrender_Even[hilbertIdx];
                detrender_Even[hilbertIdx] = hilbertTempReal;
                detrender += hilbertTempReal;
                detrender -= prev_detrender_Even;
                prev_detrender_Even = b * prev_detrender_input_Even;
                detrender += prev_detrender_Even;
                prev_detrender_input_Even = smoothedValue;
                detrender *= adjustedPrevPeriod;
                hilbertTempReal = a * detrender;
                Q1 = 0_f64 - Q1_Even[hilbertIdx];
                Q1_Even[hilbertIdx] = hilbertTempReal;
                Q1 += hilbertTempReal;
                Q1 -= prev_Q1_Even;
                prev_Q1_Even = b * prev_Q1_input_Even;
                Q1 += prev_Q1_Even;
                prev_Q1_input_Even = detrender;
                Q1 *= adjustedPrevPeriod;
                hilbertTempReal = a * I1ForEvenPrev3;
                jI = 0_f64 - jI_Even[hilbertIdx];
                jI_Even[hilbertIdx] = hilbertTempReal;
                jI += hilbertTempReal;
                jI -= prev_jI_Even;
                prev_jI_Even = b * prev_jI_input_Even;
                jI += prev_jI_Even;
                prev_jI_input_Even = I1ForEvenPrev3;
                jI *= adjustedPrevPeriod;
                hilbertTempReal = a * Q1;
                jQ = 0_f64 - jQ_Even[hilbertIdx];
                jQ_Even[hilbertIdx] = hilbertTempReal;
                jQ += hilbertTempReal;
                jQ -= prev_jQ_Even;
                prev_jQ_Even = b * prev_jQ_input_Even;
                jQ += prev_jQ_Even;
                prev_jQ_input_Even = Q1;
                jQ *= adjustedPrevPeriod;
                if { hilbertIdx += 1; hilbertIdx } == 3 {
                    hilbertIdx = 0;
                }
                Q2 = (0.2 as f64).mul_add(Q1 + jI, 0.8 * prevQ2);
                I2 = (0.2 as f64).mul_add(I1ForEvenPrev3 - jQ, 0.8 * prevI2);
                // The variable I1 is the detrender delayed for
                // 3 price bars.
                //
                // Save the current detrender value for being
                // used by the "odd" logic later.
                I1ForOddPrev3 = I1ForOddPrev2;
                I1ForOddPrev2 = detrender;
            } else {
                // Do the Hilbert Transforms for odd price bar
                hilbertTempReal = a * smoothedValue;
                detrender = 0_f64 - detrender_Odd[hilbertIdx];
                detrender_Odd[hilbertIdx] = hilbertTempReal;
                detrender += hilbertTempReal;
                detrender -= prev_detrender_Odd;
                prev_detrender_Odd = b * prev_detrender_input_Odd;
                detrender += prev_detrender_Odd;
                prev_detrender_input_Odd = smoothedValue;
                detrender *= adjustedPrevPeriod;
                hilbertTempReal = a * detrender;
                Q1 = 0_f64 - Q1_Odd[hilbertIdx];
                Q1_Odd[hilbertIdx] = hilbertTempReal;
                Q1 += hilbertTempReal;
                Q1 -= prev_Q1_Odd;
                prev_Q1_Odd = b * prev_Q1_input_Odd;
                Q1 += prev_Q1_Odd;
                prev_Q1_input_Odd = detrender;
                Q1 *= adjustedPrevPeriod;
                hilbertTempReal = a * I1ForOddPrev3;
                jI = 0_f64 - jI_Odd[hilbertIdx];
                jI_Odd[hilbertIdx] = hilbertTempReal;
                jI += hilbertTempReal;
                jI -= prev_jI_Odd;
                prev_jI_Odd = b * prev_jI_input_Odd;
                jI += prev_jI_Odd;
                prev_jI_input_Odd = I1ForOddPrev3;
                jI *= adjustedPrevPeriod;
                hilbertTempReal = a * Q1;
                jQ = 0_f64 - jQ_Odd[hilbertIdx];
                jQ_Odd[hilbertIdx] = hilbertTempReal;
                jQ += hilbertTempReal;
                jQ -= prev_jQ_Odd;
                prev_jQ_Odd = b * prev_jQ_input_Odd;
                jQ += prev_jQ_Odd;
                prev_jQ_input_Odd = Q1;
                jQ *= adjustedPrevPeriod;
                Q2 = (0.2 as f64).mul_add(Q1 + jI, 0.8 * prevQ2);
                I2 = (0.2 as f64).mul_add(I1ForOddPrev3 - jQ, 0.8 * prevI2);
                // The varaiable I1 is the detrender delayed for
                // 3 price bars.
                //
                // Save the current detrender value for being
                // used by the "even" logic later.
                I1ForEvenPrev3 = I1ForEvenPrev2;
                I1ForEvenPrev2 = detrender;
            }
            // Adjust the period for next price bar
            Re = (0.2 as f64).mul_add((I2 as f64).mul_add(prevI2, Q2 * prevQ2), 0.8 * Re);
            Im = (0.2 as f64).mul_add(I2 * prevQ2 - Q2 * prevI2, 0.8 * Im);
            prevQ2 = Q2;
            prevI2 = I2;
            tempReal = period;
            if Im != 0.0 && Re != 0.0 {
                period = 360.0 / ((Im / Re).atan() * rad2Deg);
            }
            tempReal2 = 1.5 * tempReal;
            if period > tempReal2 {
                period = tempReal2;
            }
            tempReal2 = 0.67 * tempReal;
            if period < tempReal2 {
                period = tempReal2;
            }
            if period < 6_f64 {
                period = 6.0;
            } else if period > 50_f64 {
                period = 50.0;
            }
            period = (0.2 as f64).mul_add(period, 0.8 * tempReal);
            smoothPeriod = (0.33 as f64).mul_add(period, 0.67 * smoothPeriod);
            // Compute Dominant Cycle Phase
            DCPeriod = smoothPeriod + 0.5;
            DCPeriodInt = (DCPeriod as usize) as usize;
            realPart = 0.0;
            imagPart = 0.0;
            // idx is used to iterate for up to 50 of the last
            // value of smoothPrice.
            idx = smoothPrice_Idx;
            // for( i = 0; i < DCPeriodInt; i += 1 )
            i = 0;
            while i < DCPeriodInt {
                tempReal = (i as f64) * constDeg2RadBy360 / (DCPeriodInt as f64);
                tempReal2 = smoothPrice[idx];
                realPart += (tempReal).sin() * tempReal2;
                imagPart += (tempReal).cos() * tempReal2;
                if idx == 0 {
                    idx = (50 - 1) as usize;
                } else {
                    idx -= 1;
                }
                i += 1;
            }
            tempReal = (imagPart).abs();
            if tempReal > 0.0 {
                DCPhase = (realPart / imagPart).atan() * rad2Deg;
            } else if tempReal <= 0.01 {
                if realPart < 0.0 {
                    DCPhase -= 90.0;
                } else if realPart > 0.0 {
                    DCPhase += 90.0;
                }
            }
            DCPhase += 90.0;
            // Compensate for one bar lag of the weighted moving average
            DCPhase += 360.0 / smoothPeriod;
            if imagPart < 0.0 {
                DCPhase += 180.0;
            }
            if DCPhase > 315.0 {
                DCPhase -= 360.0;
            }
            if today >= startIdx {
                outReal[outIdx] = DCPhase;
                outIdx += 1;
            }
            // Ooof... let's do the next price bar now!
            smoothPrice_Idx += 1;
            if smoothPrice_Idx > maxIdx_smoothPrice { smoothPrice_Idx = 0; }
            today += 1;
        }
        (*outNBElement) = outIdx;
        return RetCode::Success;
    }
    /// Unchecked variant of [`Core::ht_dcphase`], used for internal cross-indicator calls.
    ///
    /// Skips parameter validation and uses unchecked indexing internally. Every argument must
    /// satisfy the constraints documented on [`Core::ht_dcphase`]; 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::ht_dcphase`].
    #[inline]
    pub fn ht_dcphase_unguarded(
        &self,
        mut startIdx: usize,
        endIdx: usize,
        inReal: &[f64],
        outBegIdx: &mut usize,
        outNBElement: &mut usize,
        outReal: &mut [f64],
    ) -> RetCode {
        let mut outIdx: usize = 0_usize;
        let mut i: usize = 0_usize;
        let mut lookbackTotal: usize = 0_usize;
        let mut today: usize = 0_usize;
        let mut tempReal: f64 = 0.0_f64;
        let mut tempReal2: f64 = 0.0_f64;
        let mut adjustedPrevPeriod: f64 = 0.0_f64;
        let mut period: f64 = 0.0_f64;
        let mut trailingWMAIdx: usize = 0_usize;
        let mut periodWMASum: f64 = 0.0_f64;
        let mut periodWMASub: f64 = 0.0_f64;
        let mut trailingWMAValue: f64 = 0.0_f64;
        let mut smoothedValue: f64 = 0.0_f64;
        let mut a: f64 = 0.0_f64;
        let mut b: f64 = 0.0_f64;
        let mut hilbertTempReal: f64 = 0.0_f64;
        let mut hilbertIdx: usize = 0_usize;
        let mut detrender_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut detrender_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut detrender: f64 = 0.0_f64;
        let mut prev_detrender_Odd: f64 = 0.0_f64;
        let mut prev_detrender_Even: f64 = 0.0_f64;
        let mut prev_detrender_input_Odd: f64 = 0.0_f64;
        let mut prev_detrender_input_Even: f64 = 0.0_f64;
        let mut Q1_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut Q1_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut Q1: f64 = 0.0_f64;
        let mut prev_Q1_Odd: f64 = 0.0_f64;
        let mut prev_Q1_Even: f64 = 0.0_f64;
        let mut prev_Q1_input_Odd: f64 = 0.0_f64;
        let mut prev_Q1_input_Even: f64 = 0.0_f64;
        let mut jI_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jI_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jI: f64 = 0.0_f64;
        let mut prev_jI_Odd: f64 = 0.0_f64;
        let mut prev_jI_Even: f64 = 0.0_f64;
        let mut prev_jI_input_Odd: f64 = 0.0_f64;
        let mut prev_jI_input_Even: f64 = 0.0_f64;
        let mut jQ_Odd: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jQ_Even: [f64; 3 as usize] = [0.0_f64; 3 as usize];
        let mut jQ: f64 = 0.0_f64;
        let mut prev_jQ_Odd: f64 = 0.0_f64;
        let mut prev_jQ_Even: f64 = 0.0_f64;
        let mut prev_jQ_input_Odd: f64 = 0.0_f64;
        let mut prev_jQ_input_Even: f64 = 0.0_f64;
        let mut Q2: f64 = 0.0_f64;
        let mut I2: f64 = 0.0_f64;
        let mut prevQ2: f64 = 0.0_f64;
        let mut prevI2: f64 = 0.0_f64;
        let mut Re: f64 = 0.0_f64;
        let mut Im: f64 = 0.0_f64;
        let mut I1ForOddPrev2: f64 = 0.0_f64;
        let mut I1ForOddPrev3: f64 = 0.0_f64;
        let mut I1ForEvenPrev2: f64 = 0.0_f64;
        let mut I1ForEvenPrev3: f64 = 0.0_f64;
        let mut rad2Deg: f64 = 0.0_f64;
        let mut constDeg2RadBy360: f64 = 0.0_f64;
        let mut todayValue: f64 = 0.0_f64;
        let mut smoothPeriod: f64 = 0.0_f64;
        let mut smoothPrice: Vec<f64> = Vec::new();
        let mut smoothPrice_Idx: usize = 0;
        let mut maxIdx_smoothPrice: usize = 49;
        let mut idx: usize = 0_usize;
        let mut DCPeriodInt: usize = 0_usize;
        let mut DCPhase: f64 = 0.0_f64;
        let mut DCPeriod: f64 = 0.0_f64;
        let mut imagPart: f64 = 0.0_f64;
        let mut realPart: f64 = 0.0_f64;
        unsafe {
        assert!(endIdx < inReal.len());
        let _assertLb = self.ht_dcphase_lookback();
        let _assertStart = if startIdx > _assertLb { startIdx } else { _assertLb };
        assert!(_assertStart > endIdx || endIdx - _assertStart < outReal.len());
        a = 0.0962;
        b = 0.5769;
        smoothPrice = vec![0.0_f64; maxIdx_smoothPrice + 1];
        smoothPrice_Idx = 0;
        tempReal = (1_f64).atan();
        rad2Deg = 45.0 / tempReal;
        constDeg2RadBy360 = tempReal * 8.0;
        lookbackTotal = (63 + self.unstable_period[FuncUnstId::HtDcPhase as usize]) as usize;
        if startIdx < lookbackTotal {
            startIdx = lookbackTotal;
        }
        if startIdx > endIdx {
            (*outBegIdx) = 0;
            (*outNBElement) = 0;
            return RetCode::Success;
        }
        (*outBegIdx) = startIdx;
        trailingWMAIdx = startIdx - lookbackTotal;
        today = trailingWMAIdx;
        tempReal = *inReal.as_ptr().add({ let _v = today; today += 1; _v });
        periodWMASub = tempReal;
        periodWMASum = tempReal;
        tempReal = *inReal.as_ptr().add({ let _v = today; today += 1; _v });
        periodWMASub += tempReal;
        periodWMASum += tempReal * 2.0;
        tempReal = *inReal.as_ptr().add({ let _v = today; today += 1; _v });
        periodWMASub += tempReal;
        periodWMASum += tempReal * 3.0;
        trailingWMAValue = 0.0;
        i = 34;
        loop {
            tempReal = *inReal.as_ptr().add({ let _v = today; today += 1; _v });
            periodWMASub += tempReal;
            periodWMASub -= trailingWMAValue;
            periodWMASum += tempReal * 4.0;
            trailingWMAValue = *inReal.as_ptr().add({ let _v = trailingWMAIdx; trailingWMAIdx += 1; _v });
            smoothedValue = periodWMASum * 0.1;
            periodWMASum -= periodWMASub;
            if !({ i = i.wrapping_sub(1); i } != 0) { break; }
        }
        hilbertIdx = 0;
        *detrender_Odd.as_mut_ptr().add(0) = 0.0;
        *detrender_Odd.as_mut_ptr().add(1) = 0.0;
        *detrender_Odd.as_mut_ptr().add(2) = 0.0;
        *detrender_Even.as_mut_ptr().add(0) = 0.0;
        *detrender_Even.as_mut_ptr().add(1) = 0.0;
        *detrender_Even.as_mut_ptr().add(2) = 0.0;
        detrender = 0.0;
        prev_detrender_Odd = 0.0;
        prev_detrender_Even = 0.0;
        prev_detrender_input_Odd = 0.0;
        prev_detrender_input_Even = 0.0;
        *Q1_Odd.as_mut_ptr().add(0) = 0.0;
        *Q1_Odd.as_mut_ptr().add(1) = 0.0;
        *Q1_Odd.as_mut_ptr().add(2) = 0.0;
        *Q1_Even.as_mut_ptr().add(0) = 0.0;
        *Q1_Even.as_mut_ptr().add(1) = 0.0;
        *Q1_Even.as_mut_ptr().add(2) = 0.0;
        Q1 = 0.0;
        prev_Q1_Odd = 0.0;
        prev_Q1_Even = 0.0;
        prev_Q1_input_Odd = 0.0;
        prev_Q1_input_Even = 0.0;
        *jI_Odd.as_mut_ptr().add(0) = 0.0;
        *jI_Odd.as_mut_ptr().add(1) = 0.0;
        *jI_Odd.as_mut_ptr().add(2) = 0.0;
        *jI_Even.as_mut_ptr().add(0) = 0.0;
        *jI_Even.as_mut_ptr().add(1) = 0.0;
        *jI_Even.as_mut_ptr().add(2) = 0.0;
        jI = 0.0;
        prev_jI_Odd = 0.0;
        prev_jI_Even = 0.0;
        prev_jI_input_Odd = 0.0;
        prev_jI_input_Even = 0.0;
        *jQ_Odd.as_mut_ptr().add(0) = 0.0;
        *jQ_Odd.as_mut_ptr().add(1) = 0.0;
        *jQ_Odd.as_mut_ptr().add(2) = 0.0;
        *jQ_Even.as_mut_ptr().add(0) = 0.0;
        *jQ_Even.as_mut_ptr().add(1) = 0.0;
        *jQ_Even.as_mut_ptr().add(2) = 0.0;
        jQ = 0.0;
        prev_jQ_Odd = 0.0;
        prev_jQ_Even = 0.0;
        prev_jQ_input_Odd = 0.0;
        prev_jQ_input_Even = 0.0;
        period = 0.0;
        outIdx = 0;
        prevQ2 = 0.0;
        prevI2 = prevQ2;
        Im = 0.0;
        Re = Im;
        I1ForEvenPrev3 = 0.0;
        I1ForOddPrev3 = I1ForEvenPrev3;
        I1ForEvenPrev2 = 0.0;
        I1ForOddPrev2 = I1ForEvenPrev2;
        smoothPeriod = 0.0;
        // for( i = 0; i < 50; i += 1 )
        i = 0;
        while i < 50 {
            *smoothPrice.as_mut_ptr().add(i) = 0.0;
            i += 1;
        }
        DCPhase = 0.0;
        while today <= endIdx {
            adjustedPrevPeriod = (0.075 as f64).mul_add(period, 0.54);
            todayValue = *inReal.as_ptr().add(today);
            periodWMASub += todayValue;
            periodWMASub -= trailingWMAValue;
            periodWMASum += todayValue * 4.0;
            trailingWMAValue = *inReal.as_ptr().add({ let _v = trailingWMAIdx; trailingWMAIdx += 1; _v });
            smoothedValue = periodWMASum * 0.1;
            periodWMASum -= periodWMASub;
            *smoothPrice.as_mut_ptr().add(smoothPrice_Idx) = smoothedValue;
            if today % 2 == 0 {
                hilbertTempReal = a * smoothedValue;
                detrender = 0_f64 - *detrender_Even.as_ptr().add(hilbertIdx);
                *detrender_Even.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                detrender += hilbertTempReal;
                detrender -= prev_detrender_Even;
                prev_detrender_Even = b * prev_detrender_input_Even;
                detrender += prev_detrender_Even;
                prev_detrender_input_Even = smoothedValue;
                detrender *= adjustedPrevPeriod;
                hilbertTempReal = a * detrender;
                Q1 = 0_f64 - *Q1_Even.as_ptr().add(hilbertIdx);
                *Q1_Even.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                Q1 += hilbertTempReal;
                Q1 -= prev_Q1_Even;
                prev_Q1_Even = b * prev_Q1_input_Even;
                Q1 += prev_Q1_Even;
                prev_Q1_input_Even = detrender;
                Q1 *= adjustedPrevPeriod;
                hilbertTempReal = a * I1ForEvenPrev3;
                jI = 0_f64 - *jI_Even.as_ptr().add(hilbertIdx);
                *jI_Even.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                jI += hilbertTempReal;
                jI -= prev_jI_Even;
                prev_jI_Even = b * prev_jI_input_Even;
                jI += prev_jI_Even;
                prev_jI_input_Even = I1ForEvenPrev3;
                jI *= adjustedPrevPeriod;
                hilbertTempReal = a * Q1;
                jQ = 0_f64 - *jQ_Even.as_ptr().add(hilbertIdx);
                *jQ_Even.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                jQ += hilbertTempReal;
                jQ -= prev_jQ_Even;
                prev_jQ_Even = b * prev_jQ_input_Even;
                jQ += prev_jQ_Even;
                prev_jQ_input_Even = Q1;
                jQ *= adjustedPrevPeriod;
                if { hilbertIdx += 1; hilbertIdx } == 3 {
                    hilbertIdx = 0;
                }
                Q2 = (0.2 as f64).mul_add(Q1 + jI, 0.8 * prevQ2);
                I2 = (0.2 as f64).mul_add(I1ForEvenPrev3 - jQ, 0.8 * prevI2);
                I1ForOddPrev3 = I1ForOddPrev2;
                I1ForOddPrev2 = detrender;
            } else {
                hilbertTempReal = a * smoothedValue;
                detrender = 0_f64 - *detrender_Odd.as_ptr().add(hilbertIdx);
                *detrender_Odd.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                detrender += hilbertTempReal;
                detrender -= prev_detrender_Odd;
                prev_detrender_Odd = b * prev_detrender_input_Odd;
                detrender += prev_detrender_Odd;
                prev_detrender_input_Odd = smoothedValue;
                detrender *= adjustedPrevPeriod;
                hilbertTempReal = a * detrender;
                Q1 = 0_f64 - *Q1_Odd.as_ptr().add(hilbertIdx);
                *Q1_Odd.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                Q1 += hilbertTempReal;
                Q1 -= prev_Q1_Odd;
                prev_Q1_Odd = b * prev_Q1_input_Odd;
                Q1 += prev_Q1_Odd;
                prev_Q1_input_Odd = detrender;
                Q1 *= adjustedPrevPeriod;
                hilbertTempReal = a * I1ForOddPrev3;
                jI = 0_f64 - *jI_Odd.as_ptr().add(hilbertIdx);
                *jI_Odd.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                jI += hilbertTempReal;
                jI -= prev_jI_Odd;
                prev_jI_Odd = b * prev_jI_input_Odd;
                jI += prev_jI_Odd;
                prev_jI_input_Odd = I1ForOddPrev3;
                jI *= adjustedPrevPeriod;
                hilbertTempReal = a * Q1;
                jQ = 0_f64 - *jQ_Odd.as_ptr().add(hilbertIdx);
                *jQ_Odd.as_mut_ptr().add(hilbertIdx) = hilbertTempReal;
                jQ += hilbertTempReal;
                jQ -= prev_jQ_Odd;
                prev_jQ_Odd = b * prev_jQ_input_Odd;
                jQ += prev_jQ_Odd;
                prev_jQ_input_Odd = Q1;
                jQ *= adjustedPrevPeriod;
                Q2 = (0.2 as f64).mul_add(Q1 + jI, 0.8 * prevQ2);
                I2 = (0.2 as f64).mul_add(I1ForOddPrev3 - jQ, 0.8 * prevI2);
                I1ForEvenPrev3 = I1ForEvenPrev2;
                I1ForEvenPrev2 = detrender;
            }
            Re = (0.2 as f64).mul_add((I2 as f64).mul_add(prevI2, Q2 * prevQ2), 0.8 * Re);
            Im = (0.2 as f64).mul_add(I2 * prevQ2 - Q2 * prevI2, 0.8 * Im);
            prevQ2 = Q2;
            prevI2 = I2;
            tempReal = period;
            if Im != 0.0 && Re != 0.0 {
                period = 360.0 / ((Im / Re).atan() * rad2Deg);
            }
            tempReal2 = 1.5 * tempReal;
            if period > tempReal2 {
                period = tempReal2;
            }
            tempReal2 = 0.67 * tempReal;
            if period < tempReal2 {
                period = tempReal2;
            }
            if period < 6_f64 {
                period = 6.0;
            } else if period > 50_f64 {
                period = 50.0;
            }
            period = (0.2 as f64).mul_add(period, 0.8 * tempReal);
            smoothPeriod = (0.33 as f64).mul_add(period, 0.67 * smoothPeriod);
            DCPeriod = smoothPeriod + 0.5;
            DCPeriodInt = (DCPeriod as usize) as usize;
            realPart = 0.0;
            imagPart = 0.0;
            idx = smoothPrice_Idx;
            // for( i = 0; i < DCPeriodInt; i += 1 )
            i = 0;
            while i < DCPeriodInt {
                tempReal = (i as f64) * constDeg2RadBy360 / (DCPeriodInt as f64);
                tempReal2 = *smoothPrice.as_ptr().add(idx);
                realPart += (tempReal).sin() * tempReal2;
                imagPart += (tempReal).cos() * tempReal2;
                if idx == 0 {
                    idx = (50 - 1) as usize;
                } else {
                    idx -= 1;
                }
                i += 1;
            }
            tempReal = (imagPart).abs();
            if tempReal > 0.0 {
                DCPhase = (realPart / imagPart).atan() * rad2Deg;
            } else if tempReal <= 0.01 {
                if realPart < 0.0 {
                    DCPhase -= 90.0;
                } else if realPart > 0.0 {
                    DCPhase += 90.0;
                }
            }
            DCPhase += 90.0;
            DCPhase += 360.0 / smoothPeriod;
            if imagPart < 0.0 {
                DCPhase += 180.0;
            }
            if DCPhase > 315.0 {
                DCPhase -= 360.0;
            }
            if today >= startIdx {
                *outReal.as_mut_ptr().add(outIdx) = DCPhase;
                outIdx += 1;
            }
            smoothPrice_Idx += 1;
            if smoothPrice_Idx > maxIdx_smoothPrice { smoothPrice_Idx = 0; }
            today += 1;
        }
        (*outNBElement) = outIdx;
        return RetCode::Success;
        } // unsafe
    }
}
/***************/
/* End of File */
/***************/
