#include "sierrachart.h"
#include "scstudyfunctions.h"

/*==========================================================================*/
struct s_LevelLineConfig
{
    SCDateTime Date;
    SCString Label;
    uint32_t Color = 0;
    uint32_t Width = 0;
    float Value1 = 0;
    float Value2 = 0;

    void Clear()
    {
        Date.Clear();
        Label.Clear();
        Color = 0;
        Width = 0;
        Value1 = 0;
        Value2 = 0;
    }
};


enum TradingLevelsDataLineTypeEnum : int//must be an integer
{
    DataLineTypeDateRepeatingValues = 0
    , DataLineTypeDateFormattingValue = 1
    , DataLineTypeDateFormattingTopBottomValues = 2
};

const char* HTTP_NO_DATA_RESPONSE = "NO_DATA";

/*==========================================================================*/
int TradingLevelsStudy_RequestValuesFromServer
    ( SCStudyInterfaceRef sc
    , const SCString& BaseWebsiteURL
    , int& r_RequestState
    , const char* AlternateSymbol
    );

void TradingLevelsStudy_ResetStateForNextRequest
    ( SCStudyInterfaceRef sc
    , int& r_RequestState
    , SCDateTime& r_RequestDateTime
    , std::vector<SCString>* p_ValuesLineForDates
    , std::vector<std::vector<char*>>* p_PointersToValuesForDates
    );

unsigned int TradingLevelsStudy_GetValuesForDate
    ( SCStudyInterfaceRef sc
    , const SCDateTime& BarDate
    , float* Values
    , unsigned int ValuesArraySize
    , std::vector<std::vector<char*>>* p_PointersToValuesForDates
    , int& r_LastFoundIndex
    );

unsigned int TradingLevelsStudy_GetFormattedValuesForDate
(SCStudyInterfaceRef sc
    , const SCDateTime& BarDate
    , s_LevelLineConfig* FormattedLevelValues
    , unsigned int ArraySize
    , std::vector<std::vector<char*>>* p_PointersToValuesForDates
    , int& r_LastFoundIndex
);

void TradingLevelsStudyCore
    ( SCStudyInterfaceRef sc
    , const SCString& RequestURL
    , const int RequestIntervalInMinutes
    , std::vector<SCString>* p_ValuesLineForDates
    , std::vector<std::vector<char*>>* p_PointersToValuesForDates
    , int& r_RequestState
    , SCDateTime& r_RequestDateTime
    , int& r_ClearAtMidnight
    , bool AllowRequestLevelsFromServer
    , int& r_AwaitingNextRequestForLevels
    , const char* InAlternateSymbol
    , int& r_LastFoundLevelsArrayIndex
    , int& r_DataLineType
    );

/*==========================================================================*/
SCSFExport scsf_TradingLevelsStudy(SCStudyInterfaceRef sc)
{
    SCInputRef Input_InVersion = sc.Input[0];
    SCInputRef Input_InRequestIntervalInMinutes = sc.Input[1];
    SCInputRef Input_InUseTimeRangeForLevelsRequest = sc.Input[2];
    SCInputRef Input_InTimeRangeTimeZone = sc.Input[3];
    SCInputRef Input_InRequestStartTime = sc.Input[4];
    SCInputRef Input_InRequestEndTime = sc.Input[5];
    SCInputRef Input_InAlternateSymbol = sc.Input[6];

    const SCString RequestURL = "https://www.sierrachart.com/API.php?Service=PriceLevels";

    if (sc.SetDefaults)
    {
        sc.GraphName = "Trading Levels";

        sc.GraphRegion = 0;
        sc.ScaleRangeType = SCALE_SAMEASREGION;
        sc.ValueFormat =  VALUEFORMAT_INHERITED;
        sc.AutoLoop = 0;

        sc.StudyDescription = "Requests line level values from Web server in the format 'YYYY-MM-DD, [level_value_1], [level_value_2], [level_value_3], [level_value_4], and so on, where the level_value_# is equal to the value of the line. There can be up to SC_SUBGRAPHS_AVAILABLE level values.";


        for (int Index = 0; Index < SC_SUBGRAPHS_AVAILABLE; Index++)
        {
            SCString SubgraphName;
            SubgraphName.Format("Level %d", Index+1);
            sc.Subgraph[Index].Name = SubgraphName;
            sc.Subgraph[Index].DrawStyle = DRAWSTYLE_DASH;
            sc.Subgraph[Index].LineWidth = 2;
            sc.Subgraph[Index].PrimaryColor = RGB(0, 255, 0);
            sc.Subgraph[Index].DrawZeros = 0;  // false
            sc.Subgraph[Index].LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_CENTER | LL_VALUE_ALIGN_VALUES_SCALE;
        }

        Input_InRequestIntervalInMinutes.Name = "Request Interval in Minutes";
        Input_InRequestIntervalInMinutes.SetInt(60);
        Input_InRequestIntervalInMinutes.SetIntLimits(1, MINUTES_PER_DAY);

        Input_InUseTimeRangeForLevelsRequest.Name = "Use Time Range For Levels Request";
        Input_InUseTimeRangeForLevelsRequest.SetYesNo(false);

        Input_InTimeRangeTimeZone.Name = "Time Range Time Zone";
        Input_InTimeRangeTimeZone.SetTimeZone(TIMEZONE_NEW_YORK);

        Input_InRequestStartTime.Name = "Request Start Time";
        Input_InRequestStartTime.SetTime(0);

        Input_InRequestEndTime.Name = "Request End Time";
        Input_InRequestEndTime.SetTime(SECONDS_PER_DAY - 1);

        Input_InAlternateSymbol.Name = "Alternate Symbol";
        Input_InAlternateSymbol.SetString("");

        sc.TextInputName = "Request Identifier";

        return;
    }


    std::vector<SCString>* p_ValuesLineForDates = reinterpret_cast<std::vector<SCString>*>(sc.GetPersistentPointer(1));

    std::vector<std::vector<char*>>* p_PointersToValuesForDates = reinterpret_cast<std::vector<std::vector<char*>>*>(sc.GetPersistentPointer(2));

    int& r_RequestState = sc.GetPersistentInt(1);
    int& r_ClearAtMidnight = sc.GetPersistentInt(2);
    int& r_AwaitingNextRequestForLevels = sc.GetPersistentInt(3);
    int& r_LastFoundLevelsArrayIndex = sc.GetPersistentInt(4);
    int& r_DataLineType = sc.GetPersistentInt(5);

    SCDateTime& r_RequestDateTime = sc.GetPersistentSCDateTime(2);

    SCDateTime CurrentDateTimeInRequestTimeZone;

    bool AllowRequestLevelsFromServer = true;

    if (Input_InUseTimeRangeForLevelsRequest.GetYesNo())
    {
        CurrentDateTimeInRequestTimeZone = sc.CurrentSystemDateTime;
        CurrentDateTimeInRequestTimeZone = sc.ConvertDateTimeFromChartTimeZone(CurrentDateTimeInRequestTimeZone, Input_InTimeRangeTimeZone.GetTimeZone());

        if (CurrentDateTimeInRequestTimeZone.GetTimeInSeconds() < Input_InRequestStartTime.GetTime()
            || CurrentDateTimeInRequestTimeZone.GetTimeInSeconds() > Input_InRequestEndTime.GetTime())
            AllowRequestLevelsFromServer = false;
    }

    if (sc.IsFullRecalculation)
    {
        r_LastFoundLevelsArrayIndex = 0;
        r_DataLineType = DataLineTypeDateRepeatingValues;
    }

    TradingLevelsStudyCore
        ( sc
        , RequestURL
        , Input_InRequestIntervalInMinutes.GetInt()
        , p_ValuesLineForDates
        , p_PointersToValuesForDates
        , r_RequestState
        , r_RequestDateTime
        , r_ClearAtMidnight
        , AllowRequestLevelsFromServer
        , r_AwaitingNextRequestForLevels
        , Input_InAlternateSymbol.GetString()
        , r_LastFoundLevelsArrayIndex
        , r_DataLineType
        );
}

/*==========================================================================*/
void TradingLevelsStudyCore
( SCStudyInterfaceRef sc
, const SCString& RequestURL
, const int RequestIntervalInMinutes
, std::vector<SCString>* p_ValuesLineForDates
, std::vector<std::vector<char*>>* p_PointersToValuesForDates
, int& r_RequestState
, SCDateTime& r_RequestDateTime
, int& r_ClearAtMidnight
, bool AllowRequestLevelsFromServer
, int& r_AwaitingNextRequestForLevels
, const char* InAlternateSymbol
, int& r_LastFoundLevelsArrayIndex
, int& r_DataLineType
)
{
    if(sc.LastCallToFunction)
    {
        if(p_ValuesLineForDates != NULL)
        {
            delete p_ValuesLineForDates;
            sc.SetPersistentPointer(1, NULL);
        }

        if(p_PointersToValuesForDates != NULL)
        {
            delete p_PointersToValuesForDates;
            sc.SetPersistentPointer(2, NULL);
        }

        return;
    }

    if (p_ValuesLineForDates == NULL)
    {
        p_ValuesLineForDates = new std::vector<SCString>;

        if(p_ValuesLineForDates != NULL)
            sc.SetPersistentPointer(1, p_ValuesLineForDates);
        else
        {
            sc.AddMessageToLog("Memory allocation error.", 1);
            return;
        }
    }

    if (p_PointersToValuesForDates == NULL)
    {
        p_PointersToValuesForDates = new std::vector<std::vector< char*> >;

        if(p_PointersToValuesForDates != NULL)
            sc.SetPersistentPointer(2, p_PointersToValuesForDates);
        else
        {
            sc.AddMessageToLog("Memory allocation error.", 1);
            return;
        }
    }

    if (sc.IsFullRecalculation)
        r_ClearAtMidnight = false;


    if (AllowRequestLevelsFromServer)
    {
        //Request data on a full recalculation and also at the specified interval

        if (sc.UpdateStartIndex == 0  && r_RequestState == HTTP_REQUEST_RECEIVED)
        {
            TradingLevelsStudy_ResetStateForNextRequest(sc, r_RequestState, r_RequestDateTime, p_ValuesLineForDates, p_PointersToValuesForDates);
        }
        else if (r_RequestDateTime.IsUnset()
            || ( (sc.CurrentSystemDateTime - r_RequestDateTime)
                >= SCDateTime::MINUTES(RequestIntervalInMinutes))
            )// Request interval has elapsed
        {
            TradingLevelsStudy_ResetStateForNextRequest(sc, r_RequestState, r_RequestDateTime, p_ValuesLineForDates, p_PointersToValuesForDates);
        }

        if (TradingLevelsStudy_RequestValuesFromServer(sc, RequestURL, r_RequestState, InAlternateSymbol))
        {
            if (r_RequestState == HTTP_REQUEST_MADE)
                r_AwaitingNextRequestForLevels = false;

            return;//Return here since we need to wait for the response
        }
    }


    if (sc.HTTPRequestID != 0)//response received
    {
        r_RequestState = HTTP_REQUEST_RECEIVED;

        if (sc.HTTPResponse == ACSIL_HTTP_REQUEST_ERROR_TEXT
            || sc.HTTPResponse == ACSIL_HTTP_EMPTY_RESPONSE_TEXT)
        {
            sc.AddMessageToLog("There was an error requesting data from the server.", true);
        }

        if (sc.UpdateStartIndex == 0 && sc.HTTPResponse == HTTP_NO_DATA_RESPONSE)
            sc.AddMessageToLog("There are no price levels for the given parameters.", false);

        if (strstr(sc.HTTPResponse.GetChars(), "CLEAR_AT_MIDNIGHT") != NULL)
        {
            sc.AddMessageToLog("Received clear at midnight command.", false);
            r_ClearAtMidnight = true;
        }
    }

    if (r_RequestState != HTTP_REQUEST_RECEIVED)
        return;

    SCDateTime StartIndexDate = sc.BaseDateTimeIn[sc.UpdateStartIndex].GetDate();
    SCDateTime LastBarDate = sc.BaseDateTimeIn[sc.ArraySize - 1].GetDate();

    if (r_ClearAtMidnight && StartIndexDate != LastBarDate)
    {
        //clear existing levels
        p_ValuesLineForDates->clear();
        p_PointersToValuesForDates->clear();

        for (int BarIndex = sc.ArraySize - 1; BarIndex >= 0; --BarIndex)
        {
            for (unsigned int LevelIndex = 0; LevelIndex < SC_SUBGRAPHS_AVAILABLE; LevelIndex++)
            {
                sc.Subgraph[LevelIndex][BarIndex] = 0;
            }
        }

        r_ClearAtMidnight = false;//Prevent this from happening on next calculation.
        r_AwaitingNextRequestForLevels = true;

    }

    if (r_AwaitingNextRequestForLevels)
        return;

    if (sc.HTTPResponse == HTTP_NO_DATA_RESPONSE)
        return;

    bool FullRecalculate = false;

    if(p_ValuesLineForDates->empty())
    {
        r_LastFoundLevelsArrayIndex = 0;

        SCString  DataLineTypeDateFormattingValueString("Date, Label, Color, Width, Value");
        SCString  DataLineTypeDateFormattingTopBottomValuesString("Date, Label, Color, Width, TopValue, BottomValue");

        if (sc.HTTPResponse.GetSubString(DataLineTypeDateFormattingValueString.GetLength(), 0)
            == DataLineTypeDateFormattingValueString)
        {
            r_DataLineType = DataLineTypeDateFormattingValue;
        }
        else if (sc.HTTPResponse.GetSubString(DataLineTypeDateFormattingTopBottomValuesString.GetLength(), 0)
            == DataLineTypeDateFormattingTopBottomValuesString)
        {
            r_DataLineType = DataLineTypeDateFormattingTopBottomValues;
        }

        sc.HTTPResponse.ParseLines(*p_ValuesLineForDates);

        SCString Message;
        Message.Format("Received %d price level lines of data from server.", p_ValuesLineForDates->size());
        sc.AddMessageToLog(Message, false);

        std::vector<char *> EmptyVector;

        for (int Index = 0; Index < static_cast<int>(p_ValuesLineForDates->size()); Index++)
        {
            p_PointersToValuesForDates->push_back(EmptyVector);
            p_ValuesLineForDates->at(Index).Tokenize(",", p_PointersToValuesForDates->back());
        }

        FullRecalculate = true;
    }

    if(p_PointersToValuesForDates->empty())
        return;

    if (FullRecalculate)
        sc.UpdateStartIndex = 0;

    float LevelValues[SC_SUBGRAPHS_AVAILABLE] = {};
    s_LevelLineConfig FormattedLevelValues[SC_SUBGRAPHS_AVAILABLE];

    SCDateTime PriorDate;


    uint32_t MaximumLevelsUsedPerDay = 0;
    uint32_t NumberUsedLevels = 0;

    for (int BarIndex = sc.UpdateStartIndex; BarIndex < sc.ArraySize; BarIndex++)
    {
        SCDateTime BarIndexDate = sc.GetTradingDayDate(sc.BaseDateTimeIn[BarIndex]);

        if (r_DataLineType == DataLineTypeDateRepeatingValues)
        {
            if (PriorDate != BarIndexDate)
            {
                NumberUsedLevels = TradingLevelsStudy_GetValuesForDate(sc, BarIndexDate, LevelValues, SC_SUBGRAPHS_AVAILABLE, p_PointersToValuesForDates, r_LastFoundLevelsArrayIndex);

                if (NumberUsedLevels > MaximumLevelsUsedPerDay)
                    MaximumLevelsUsedPerDay = NumberUsedLevels;

                PriorDate = BarIndexDate;
            }


            for (uint32_t LevelIndex = 0; LevelIndex < NumberUsedLevels; LevelIndex++)
                sc.Subgraph[LevelIndex][BarIndex] = LevelValues[LevelIndex];

        }
        else if (r_DataLineType == DataLineTypeDateFormattingValue)
        {
            if (PriorDate != BarIndexDate)
            {
                NumberUsedLevels = TradingLevelsStudy_GetFormattedValuesForDate(sc, BarIndexDate, FormattedLevelValues, SC_SUBGRAPHS_AVAILABLE, p_PointersToValuesForDates, r_LastFoundLevelsArrayIndex);

                for (uint32_t LevelIndex = 0; LevelIndex < NumberUsedLevels; LevelIndex++)
                {
                    sc.Subgraph[LevelIndex].Name = FormattedLevelValues[LevelIndex].Label;
                    sc.Subgraph[LevelIndex].LineWidth = FormattedLevelValues[LevelIndex].Width;
                    sc.Subgraph[LevelIndex].PrimaryColor = FormattedLevelValues[LevelIndex].Color;
                }

                if (NumberUsedLevels > MaximumLevelsUsedPerDay)
                    MaximumLevelsUsedPerDay = NumberUsedLevels;

                PriorDate = BarIndexDate;
            }

            for (uint32_t LevelIndex = 0; LevelIndex < NumberUsedLevels; LevelIndex++)
                sc.Subgraph[LevelIndex][BarIndex] = FormattedLevelValues[LevelIndex].Value1;

        }
        else if (r_DataLineType == DataLineTypeDateFormattingTopBottomValues)
        {
            if (PriorDate != BarIndexDate)
            {
                NumberUsedLevels = TradingLevelsStudy_GetFormattedValuesForDate(sc, BarIndexDate, FormattedLevelValues, SC_SUBGRAPHS_AVAILABLE, p_PointersToValuesForDates, r_LastFoundLevelsArrayIndex);

                if (NumberUsedLevels > (SC_SUBGRAPHS_AVAILABLE / 2))
                    NumberUsedLevels = (SC_SUBGRAPHS_AVAILABLE / 2);

                for (uint32_t LevelIndex = 0; LevelIndex < NumberUsedLevels; LevelIndex++)
                {
                    int SubgraphIndex = LevelIndex * 2;
                    sc.Subgraph[SubgraphIndex].Name = FormattedLevelValues[LevelIndex].Label;
                    sc.Subgraph[SubgraphIndex].Name += " Top";
                    sc.Subgraph[SubgraphIndex].LineWidth = FormattedLevelValues[LevelIndex].Width;
                    sc.Subgraph[SubgraphIndex].PrimaryColor = FormattedLevelValues[LevelIndex].Color;

                    uint16_t& r_DrawStyleTop = sc.Subgraph[SubgraphIndex].DrawStyle;
                    uint16_t& r_DrawStyleBottom = sc.Subgraph[SubgraphIndex + 1].DrawStyle;

                    if (r_DrawStyleTop != DRAWSTYLE_FILL_RECTANGLE_TOP &&
                        r_DrawStyleTop != DRAWSTYLE_TRANSPARENT_FILL_RECTANGLE_TOP)
                    {
                        r_DrawStyleTop = DRAWSTYLE_TRANSPARENT_FILL_RECTANGLE_TOP;
                        r_DrawStyleBottom = DRAWSTYLE_TRANSPARENT_FILL_RECTANGLE_BOTTOM;
                    }

                    if (r_DrawStyleTop == DRAWSTYLE_FILL_RECTANGLE_TOP)
                        r_DrawStyleBottom = DRAWSTYLE_FILL_RECTANGLE_BOTTOM;
                    else if (r_DrawStyleTop == DRAWSTYLE_TRANSPARENT_FILL_RECTANGLE_TOP)
                        r_DrawStyleBottom = DRAWSTYLE_TRANSPARENT_FILL_RECTANGLE_BOTTOM;

                    sc.Subgraph[SubgraphIndex + 1].Name = FormattedLevelValues[LevelIndex].Label;
                    sc.Subgraph[SubgraphIndex + 1].Name += " Bottom";
                    sc.Subgraph[SubgraphIndex + 1].LineWidth = FormattedLevelValues[LevelIndex].Width;
                    sc.Subgraph[SubgraphIndex + 1].PrimaryColor = FormattedLevelValues[LevelIndex].Color;

                }

                //if (NumberUsedLevels > MaximumLevelsUsedPerDay)
                //  MaximumLevelsUsedPerDay = NumberUsedLevels;

                PriorDate = BarIndexDate;
            }

            for (uint32_t LevelIndex = 0; LevelIndex < NumberUsedLevels; LevelIndex++)
            {
                int SubgraphIndex = LevelIndex * 2;
                sc.Subgraph[SubgraphIndex][BarIndex] = FormattedLevelValues[LevelIndex].Value1;
                sc.Subgraph[SubgraphIndex + 1][BarIndex] = FormattedLevelValues[LevelIndex].Value2;
            }

        }
    }

    if (FullRecalculate && r_DataLineType != DataLineTypeDateFormattingTopBottomValues)
    {
        for (uint32_t Index = 0; Index < SC_SUBGRAPHS_AVAILABLE; Index++)
        {
            if (Index < MaximumLevelsUsedPerDay
                && !sc.IsVisibleSubgraphDrawStyle(sc.Subgraph[Index].DrawStyle))
            {
                sc.Subgraph[Index].DrawStyle = DRAWSTYLE_DASH;
                sc.Subgraph[Index].DisplayNameValueInDataLine = true;
                sc.Subgraph[Index].DisplayNameValueInWindowsFlags = true;
            }
            else if (Index >= MaximumLevelsUsedPerDay)
            {
                sc.Subgraph[Index].DrawStyle = DRAWSTYLE_IGNORE;
                sc.Subgraph[Index].DisplayNameValueInDataLine = false;
                sc.Subgraph[Index]. DisplayNameValueInWindowsFlags = false;
            }
        }
    }
}

/*==========================================================================*/
//Returns 1 if request has been made. Returns 0 if request has not been made.
int TradingLevelsStudy_RequestValuesFromServer
( SCStudyInterfaceRef sc
, const SCString& BaseWebsiteURL
, int& r_RequestState
, const char* AlternateSymbol
)
{
    SCString FullURL;

    if (r_RequestState != HTTP_REQUEST_NOT_SENT)
        return 0;


    if (sc.TextInput.IsEmpty())
        return 0;

    const char* RequestSymbol = NULL;

    if (AlternateSymbol != NULL && AlternateSymbol[0] != '\0')
        RequestSymbol = AlternateSymbol;
    else
        RequestSymbol = sc.Symbol.GetChars();

    FullURL.Format
    ("%s&Username=%s&Symbol=%s&SCDLLName=%s"
        , BaseWebsiteURL.GetChars()
        , sc.UserName().GetChars()
        , RequestSymbol
        , sc.TextInput.GetChars()
    );

    if (!sc.MakeHTTPRequest(FullURL))
    {
        sc.AddMessageToLog("Error making HTTP Request.", true);
        r_RequestState = HTTP_REQUEST_ERROR;
    }
    else
    {
        r_RequestState = HTTP_REQUEST_MADE;
        SCString LogMessage("Requesting data from Trading Levels server: ");
        LogMessage += FullURL;
        sc.AddMessageToLog(LogMessage, false);
    }

    return 1;

}

/*==========================================================================*/
void TradingLevelsStudy_ResetStateForNextRequest
( SCStudyInterfaceRef sc
, int& r_RequestState
, SCDateTime& r_RequestDateTime
, std::vector<SCString>* p_ValuesLineForDates
, std::vector<std::vector<char*>>* p_PointersToValuesForDates
)
{
    p_ValuesLineForDates->clear();
    p_PointersToValuesForDates->clear();

    r_RequestState = HTTP_REQUEST_NOT_SENT;
    r_RequestDateTime = sc.CurrentSystemDateTime;
}
/*==========================================================================*/
unsigned int TradingLevelsStudy_GetValuesForDate
( SCStudyInterfaceRef sc
, const SCDateTime& BarDate
, float* Values
, unsigned int ValuesArraySize
, std::vector<std::vector<char*>>* p_PointersToValuesForDates
, int& r_LastFoundIndex
)
{
    //Clean array
    memset(Values, 0, sizeof(float) * ValuesArraySize);

    if (p_PointersToValuesForDates->empty())
        return 0;

    unsigned int NumberLevels = 0;
    const int EndIndex = static_cast<int>(p_PointersToValuesForDates->size());

    for(; r_LastFoundIndex < EndIndex; r_LastFoundIndex++)
    {
        std::vector<char*>& Fields = p_PointersToValuesForDates->at(r_LastFoundIndex);

        if (Fields.empty())
            continue;

        SCDateTime SourceDataLineDate = sc.DateStringToSCDateTime(Fields[0]);

        if (SourceDataLineDate < BarDate)
            continue;

        if (SourceDataLineDate > BarDate)
            return NumberLevels;//r_LastFoundIndex will be used on the next entry and continue from the correct index.


        int FieldsSize = static_cast<unsigned int>(Fields.size());

        for (int ItemIndex = 1; ItemIndex < FieldsSize; ItemIndex++)
        {
            Values[NumberLevels] = static_cast<float>(sc.StringToDouble(Fields[ItemIndex]));
            NumberLevels++;

            if (NumberLevels >= ValuesArraySize)
                break;
        }

        break;
    }

    return NumberLevels;
}
/*==========================================================================*/
unsigned int TradingLevelsStudy_GetFormattedValuesForDate
(SCStudyInterfaceRef sc
    , const SCDateTime& BarDate
    , s_LevelLineConfig* FormattedLevelValues
    , unsigned int ArraySize
    , std::vector<std::vector<char*>>* p_PointersToValuesForDates
    , int& r_LastFoundIndex
)
{
    //Clean array
    for (uint32_t Index = 0; Index < ArraySize; Index++)
    {
        FormattedLevelValues[Index].Clear();
    }

    if (p_PointersToValuesForDates->empty())
        return 0;

    unsigned int LevelIndex = 0;
    const int EndIndex = static_cast<int>(p_PointersToValuesForDates->size());
    for (; r_LastFoundIndex < EndIndex; r_LastFoundIndex++)
    {
        std::vector<char*>& Fields = p_PointersToValuesForDates->at(r_LastFoundIndex);

        if (Fields.empty())
            continue;

        //"Date, Label, Color, Width, Value"
        //"Date, Label, Color, Width, TopValue, BottomValue"
        SCDateTime SourceDataLineDate = sc.DateStringToSCDateTime(Fields[0]);

        if (SourceDataLineDate < BarDate)
            continue;

        if (SourceDataLineDate > BarDate)
            return LevelIndex;//r_LastFoundIndex will be used on the next entry and continue from the correct index.

        if (Fields.size() < 6)
            continue;

        FormattedLevelValues[LevelIndex].Date = SourceDataLineDate;
        FormattedLevelValues[LevelIndex].Label = Fields[1];
        FormattedLevelValues[LevelIndex].Color = atoi(Fields[2]);
        const int ColorValue = FormattedLevelValues[LevelIndex].Color;
        uint8_t Red = (ColorValue & 0xff0000) >> 16;
        uint8_t Green = (ColorValue & 0xff00) >> 8;
        uint8_t Blue = ColorValue & 0xff;
        FormattedLevelValues[LevelIndex].Color = RGB(Red, Green, Blue);

        FormattedLevelValues[LevelIndex].Width = atoi(Fields[3]);
        FormattedLevelValues[LevelIndex].Value1 = static_cast<float>(atof(Fields[4]));

        if(Fields.size() >= 6)
            FormattedLevelValues[LevelIndex].Value2 = static_cast<float>(atof(Fields[5]));

        LevelIndex++;

        if (LevelIndex >= ArraySize)
            break;
    }

    return LevelIndex;//Num levels
}