/*
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "components/ui_time_picker.h"
#include <cstdio>
#include <ctime>
#include "draw/draw_rect.h"
#include "gfx_utils/graphic_log.h"
#include "securec.h"
#include "themes/theme_manager.h"

namespace OHOS {
UITimePicker::UITimePicker()
    : selectedValue_{0},
      selectedHour_{0},
      selectedMinute_{0},
      selectedSecond_{0},
      secVisible_(false),
      loopState_{false},
      pickerWidth_(0),
      itemsHeight_(0),
      xPos_(0),
      backgroundFontSize_(0),
      highlightFontSize_(0),
      backgroundFontName_(nullptr),
      highlightFontName_(nullptr),
      pickerListener_(this),
      timePickerListener_(nullptr)
{
    Theme* theme = ThemeManager::GetInstance().GetCurrent();
    if (theme != nullptr) {
        style_ = &(theme->GetPickerBackgroundStyle());
    } else {
        style_ = &(StyleDefault::GetPickerBackgroundStyle());
    }
    backgroundFontId_ = style_->font_;
    backgroundColor_ = style_->textColor_;
    if (theme != nullptr) {
        style_ = &(theme->GetPickerHighlightStyle());
    } else {
        style_ = &(StyleDefault::GetPickerHighlightStyle());
    }
#if ENABLE_FOCUS_MANAGER
    focusable_ = true;
#endif
    highlightFontId_ = style_->font_;
    highlightColor_ = style_->textColor_;

    hourPicker_ = nullptr;
    minutePicker_ = nullptr;
    secondPicker_ = nullptr;
}

UITimePicker::~UITimePicker()
{
    DeInitTimePicker();
    if (backgroundFontName_ != nullptr) {
        UIFree(backgroundFontName_);
        backgroundFontName_ = nullptr;
    }

    if (highlightFontName_ != nullptr) {
        UIFree(highlightFontName_);
        highlightFontName_ = nullptr;
    }
}

void UITimePicker::InitTimePicker()
{
    xPos_ = 0;
    if (secVisible_) {
        pickerWidth_ = GetWidth() / SEC_VISIBLE_COUNT;
        InitPicker(hourPicker_, TIME_START, HOUR_END);
        xPos_ = pickerWidth_;
        InitPicker(minutePicker_, TIME_START, MIN_END);
        xPos_ *= (SEC_VISIBLE_COUNT - 1);
        InitPicker(secondPicker_, TIME_START, SEC_END);
        if (secondPicker_ != nullptr) {
            secondPicker_->SetLoopState(loopState_[PICKER_SEC]);
        }
    } else {
        pickerWidth_ = GetWidth() / SEC_INVISIBLE_COUNT;
        InitPicker(hourPicker_, TIME_START, HOUR_END);
        xPos_ = pickerWidth_;
        InitPicker(minutePicker_, TIME_START, MIN_END);
    }
    if (hourPicker_ != nullptr) {
        hourPicker_->SetLoopState(loopState_[PICKER_HOUR]);
    }
    if (minutePicker_ != nullptr) {
        minutePicker_->SetLoopState(loopState_[PICKER_MIN]);
    }

    RefreshSelected(selectedValue_);
}

void UITimePicker::DeInitTimePicker()
{
    DeInitPicker(secondPicker_);
    DeInitPicker(minutePicker_);
    DeInitPicker(hourPicker_);
}

void UITimePicker::RefreshTimePicker()
{
    DeInitTimePicker();
    InitTimePicker();
}

void UITimePicker::InitPicker(UIPicker*& picker, int16_t start, int16_t end)
{
    picker = new UIPicker();
    if (picker == nullptr) {
        GRAPHIC_LOGE("new UIPicker fail");
        return;
    }
    picker->SetPosition(xPos_, 0, pickerWidth_, GetHeight());
    picker->SetItemHeight(itemsHeight_);
    picker->SetFontId(backgroundFontId_, highlightFontId_);
    if ((backgroundFontName_ == nullptr) || (highlightFontName_ == nullptr)) {
        picker->SetFontId(backgroundFontId_, highlightFontId_);
    } else {
        picker->SetBackgroundFont(backgroundFontName_, backgroundFontSize_);
        picker->SetHighlightFont(highlightFontName_, highlightFontSize_);
    }
    picker->SetTextColor(backgroundColor_, highlightColor_);
    picker->SetValues(start, end);
    picker->RegisterSelectedListener(&pickerListener_);
    Add(picker);

#if ENABLE_ROTATE_INPUT
    if (end == HOUR_END) {
        picker->GetChildrenHead()->SetViewId(HOUR_LIST_NAME);
    } else if (end == MIN_END && secondPicker_ == nullptr) {
        picker->GetChildrenHead()->SetViewId(MIN_LIST_NAME);
    } else if (end == SEC_END) {
        picker->GetChildrenHead()->SetViewId(SEC_LIST_NAME);
    }
#endif
}

void UITimePicker::DeInitPicker(UIPicker*& picker)
{
    if (picker != nullptr) {
        Remove(picker);
        picker->ClearValues();
        delete picker;
        picker = nullptr;
    }
}

void UITimePicker::TimeSelectedCallback()
{
    uint16_t hourSelect = hourPicker_->GetSelected();
    uint16_t minSelect = minutePicker_->GetSelected();
    GetValueByIndex(selectedHour_, BUF_SIZE, hourSelect, TIME_START, HOUR_END);
    GetValueByIndex(selectedMinute_, BUF_SIZE, minSelect, TIME_START, MIN_END);

    if (memset_s(selectedValue_, SELECTED_VALUE_SIZE, 0, SELECTED_VALUE_SIZE) != EOK) {
        return;
    }

    if (secVisible_) {
        uint16_t secSelect = secondPicker_->GetSelected();
        GetValueByIndex(selectedSecond_, BUF_SIZE, secSelect, TIME_START, SEC_END);
        if (sprintf_s(selectedValue_, SELECTED_VALUE_SIZE, "%s:%s:%s",
            selectedHour_, selectedMinute_, selectedSecond_) < 0) {
            return;
        }
    } else {
        if (sprintf_s(selectedValue_, SELECTED_VALUE_SIZE, "%s:%s", selectedHour_, selectedMinute_) < 0) {
            return;
        }
    }

    if (timePickerListener_ != nullptr) {
        timePickerListener_->OnTimePickerStoped(*this);
    }
}

void UITimePicker::GetValueByIndex(char* value, uint8_t len, uint16_t index, int16_t start, int16_t end)
{
    if ((value != nullptr) && (index < end - start + 1)) {
        if (sprintf_s(value, len, "%02u", index) < 0) {
            return;
        }
    }
}

bool UITimePicker::SetSelected(const char* value)
{
    if (value == nullptr) {
        return false;
    }

    if (memset_s(selectedValue_, SELECTED_VALUE_SIZE, 0, SELECTED_VALUE_SIZE) != EOK) {
        return false;
    }

    if (strcpy_s(selectedValue_, SELECTED_VALUE_SIZE, value) != EOK) {
        return false;
    }
    if (secVisible_) {
        if (sscanf_s(value, "%[^:]%*c%[^:]%*c%[^\n]", selectedHour_, BUF_SIZE,
                     selectedMinute_, BUF_SIZE, selectedSecond_, BUF_SIZE) < 3) { // 3: three variables
            return false;
        }
    } else {
        if (sscanf_s(value, "%[^:]%*c%[^\n]", selectedHour_, BUF_SIZE,
                     selectedMinute_, BUF_SIZE) < 2) { // 2: two variables
            return false;
        }
    }
    return RefreshSelected(selectedValue_);
}

bool UITimePicker::RefreshSelected(const char* value)
{
    uint32_t hourSelect;
    uint32_t minSelect;

    if (value == nullptr) {
        return false;
    }

    if (secVisible_) {
        uint32_t secSelect;
        // 3: three variables
        if (sscanf_s(value, "%u:%u:%u", &hourSelect, &minSelect, &secSelect) < 3) {
            return false;
        }
        secondPicker_->SetSelected(secSelect);
    } else {
        if (sscanf_s(value, "%u:%u", &hourSelect, &minSelect) < 2) { // 2: two variables
            return false;
        }
    }

    hourPicker_->SetSelected(hourSelect);
    minutePicker_->SetSelected(minSelect);
    return true;
}

bool UITimePicker::OnPressEvent(const PressEvent& event)
{
    if (event.GetCurrentPos().x < (GetX() + hourPicker_->GetX() + hourPicker_->GetWidth())) {
        hourPicker_->RequestFocus();
    } else if (event.GetCurrentPos().x < (GetX() + minutePicker_->GetX() + minutePicker_->GetWidth())) {
        minutePicker_->RequestFocus();
    } else if (event.GetCurrentPos().x < (GetX() + secondPicker_->GetX() + secondPicker_->GetWidth())) {
        secondPicker_->RequestFocus();
    }
    return UIView::OnPressEvent(event);
}

void UITimePicker::SetItemHeight(int16_t height)
{
    itemsHeight_ = height;
    RefreshTimePicker();
}

void UITimePicker::EnableSecond(bool state)
{
    secVisible_ = state;
    RefreshTimePicker();
}

void UITimePicker::SetTextStyle(uint16_t backgroundFontId,
                                uint16_t highlightFontId,
                                ColorType backgroundColor,
                                ColorType highlightColor)
{
    highlightFontId_ = highlightFontId;
    if (highlightFontName_ != nullptr) {
        UIFree(highlightFontName_);
        highlightFontName_ = nullptr;
    }

    backgroundFontId_ = backgroundFontId;
    if (backgroundFontName_ != nullptr) {
        UIFree(backgroundFontName_);
        backgroundFontName_ = nullptr;
    }

    highlightColor_ = highlightColor;
    backgroundColor_ = backgroundColor;
    RefreshTimePicker();
}

void UITimePicker::SetTextColor(ColorType backgroundColor, ColorType highlightColor)
{
    backgroundColor_ = backgroundColor;
    highlightColor_ = highlightColor;
    RefreshTimePicker();
}

void UITimePicker::SetBackgroundFont(const char* name, uint8_t size)
{
    Text::SetFont(name, size, backgroundFontName_, backgroundFontSize_);
    RefreshTimePicker();
}

void UITimePicker::SetHighlightFont(const char* name, uint8_t size)
{
    Text::SetFont(name, size, highlightFontName_, highlightFontSize_);
    RefreshTimePicker();
}

void UITimePicker::SetWidth(int16_t width)
{
    UIView::SetWidth(width);
    RefreshTimePicker();
}

void UITimePicker::SetHeight(int16_t height)
{
    UIView::SetHeight(height);
    RefreshTimePicker();
}

void UITimePicker::SetLoopState(const uint8_t pickerType, bool state)
{
    switch (pickerType) {
        case PICKER_HOUR:
            loopState_[PICKER_HOUR] = state;
            break;
        case PICKER_MIN:
            loopState_[PICKER_MIN] = state;
            break;
        case PICKER_SEC:
            loopState_[PICKER_SEC] = state;
            break;
        default:
            return;
    }
    RefreshTimePicker();
}
}