/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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.
 */
package com.android.tools.property.panel.impl.model

import com.android.SdkConstants.*
import com.android.tools.adtui.workbench.PropertiesComponentMock
import com.android.tools.property.panel.impl.model.util.FakePropertyEditorModel
import com.android.tools.property.panel.impl.model.util.FakePropertyItem
import com.google.common.truth.Truth.assertThat
import com.intellij.ide.util.PropertiesComponent
import com.intellij.util.text.Matcher
import com.intellij.util.ui.UIUtil
import icons.StudioIcons
import org.junit.Test

private const val OUTER_EXPANDED_BY_DEFAULT = true
private const val INNER_EXPANDED_BY_DEFAULT = false
private const val OUTER_GROUP_NAME = "OuterGroup"
private const val INNER_GROUP_NAME = "InnerGroup"

class CollapsibleLabelModelTest {

  class Labels(val properties: PropertiesComponent = PropertiesComponentMock()) {
    private val colorProperty = FakePropertyItem(ANDROID_URI, ATTR_COLOR, "#00FF00")
    private val backgroundTintProperty = FakePropertyItem(TOOLS_URI, ATTR_BACKGROUND_TINT, "#00FF00")
    private val textProperty = FakePropertyItem(AUTO_URI, ATTR_TEXT, "hello")
    private val someProperty = FakePropertyItem("SomeNamespace", "some", "world")
    private val styleProperty = FakePropertyItem("", ATTR_STYLE, null)

    private val colorEditor = FakePropertyEditorModel(colorProperty)
    private val backgroundTintEditor = FakePropertyEditorModel(backgroundTintProperty)
    private val textEditor = FakePropertyEditorModel(textProperty)
    private val someEditor = FakePropertyEditorModel(someProperty)
    private val styleEditor = FakePropertyEditorModel(styleProperty)

    val outerGroup = CollapsibleLabelModel(OUTER_GROUP_NAME, null, true, properties)
    val colorItem = CollapsibleLabelModel(ATTR_COLOR, colorEditor, true, properties)
    val innerGroup = CollapsibleLabelModel(INNER_GROUP_NAME, null, true, properties)
    val backgroundTintItem = CollapsibleLabelModel(ATTR_BACKGROUND_TINT, backgroundTintEditor, true, properties)
    val textItem = CollapsibleLabelModel(ATTR_TEXT, textEditor, true, properties)
    val someItem = CollapsibleLabelModel("some", someEditor, true, properties)
    val styleItem = CollapsibleLabelModel(ATTR_STYLE, styleEditor, true, properties)

    init {
      outerGroup.makeExpandable(OUTER_EXPANDED_BY_DEFAULT)
      outerGroup.addChild(colorItem)
      outerGroup.addChild(innerGroup)
      outerGroup.addChild(someItem)
      outerGroup.addChild(styleItem)
      innerGroup.makeExpandable(INNER_EXPANDED_BY_DEFAULT)
      innerGroup.addChild(backgroundTintItem)
      innerGroup.addChild(textItem)
    }
  }

  @Test
  fun testCollapseHidesInnerChildren() {
    val test = Labels()
    test.innerGroup.expanded = true
    test.outerGroup.expanded = false
    assertThat(test.outerGroup.visible).isTrue()
    assertThat(test.colorItem.visible).isFalse()
    assertThat(test.someItem.visible).isFalse()
    assertThat(test.innerGroup.visible).isFalse()
    assertThat(test.backgroundTintItem.visible).isFalse()
    assertThat(test.textItem.visible).isFalse()
  }

  @Test
  fun testCollapseWithInnerGroupCollapsed() {
    val test = Labels()
    test.outerGroup.expanded = false
    assertThat(test.outerGroup.visible).isTrue()
    assertThat(test.colorItem.visible).isFalse()
    assertThat(test.someItem.visible).isFalse()
    assertThat(test.innerGroup.visible).isFalse()
    assertThat(test.backgroundTintItem.visible).isFalse()
    assertThat(test.textItem.visible).isFalse()
  }

  @Test
  fun testExpandRestoresInnerChildrenWhenExpanded() {
    val test = Labels()
    test.innerGroup.expanded = true
    test.outerGroup.expanded = false
    test.outerGroup.expanded = true
    assertThat(test.outerGroup.visible).isTrue()
    assertThat(test.colorItem.visible).isTrue()
    assertThat(test.someItem.visible).isTrue()
    assertThat(test.innerGroup.visible).isTrue()
    assertThat(test.backgroundTintItem.visible).isTrue()
    assertThat(test.textItem.visible).isTrue()
  }

  @Test
  fun testExpandRestoredInnerChildrenWhenCollapsed() {
    val test = Labels()
    test.outerGroup.expanded = false
    test.outerGroup.expanded = true
    assertThat(test.outerGroup.visible).isTrue()
    assertThat(test.colorItem.visible).isTrue()
    assertThat(test.someItem.visible).isTrue()
    assertThat(test.innerGroup.visible).isTrue()
    assertThat(test.backgroundTintItem.visible).isFalse()
    assertThat(test.textItem.visible).isFalse()
  }

  @Test
  fun testIconOfExpandedGroup() {
    val test = Labels()
    assertThat(test.outerGroup.icon).isEqualTo(UIUtil.getTreeExpandedIcon())
  }

  @Test
  fun testIconOfCollapsedGroup() {
    val test = Labels()
    test.outerGroup.expanded = false
    assertThat(test.outerGroup.icon).isEqualTo(UIUtil.getTreeCollapsedIcon())
  }

  @Test
  fun testIconOfPropertyItemWithoutNamespace() {
    val test = Labels()
    assertThat(test.styleItem.icon).isNull()
  }

  @Test
  fun testIconOfAndroidPropertyItem() {
    val test = Labels()
    assertThat(test.colorItem.icon).isNull()
  }

  @Test
  fun testIconOfToolsPropertyItem() {
    val test = Labels()
    assertThat(test.backgroundTintItem.icon).isEqualTo(StudioIcons.LayoutEditor.Properties.TOOLS_ATTRIBUTE)
  }

  @Test
  fun testIconOfApplicationPropertyItem() {
    val test = Labels()
    assertThat(test.textItem.icon).isNull()
  }

  @Test
  fun testUpdatePropertiesWhenCollapsing() {
    val test = Labels()
    test.outerGroup.expanded = false
    test.innerGroup.expanded = false
    assertThat(test.properties.getBoolean(KEY_PREFIX + test.outerGroup.name, OUTER_EXPANDED_BY_DEFAULT)).isFalse()
    assertThat(test.properties.getBoolean(KEY_PREFIX + test.innerGroup.name, INNER_EXPANDED_BY_DEFAULT)).isFalse()
  }

  @Test
  fun testUpdatePropertiesWhenExpanded() {
    val test = Labels()
    test.outerGroup.expanded = true
    test.innerGroup.expanded = true
    assertThat(test.properties.getBoolean(KEY_PREFIX + test.outerGroup.name, OUTER_EXPANDED_BY_DEFAULT)).isTrue()
    assertThat(test.properties.getBoolean(KEY_PREFIX + test.innerGroup.name, INNER_EXPANDED_BY_DEFAULT)).isTrue()
  }

  @Test
  fun testInitialExpandedStateIsReadFromProperties() {
    val properties = PropertiesComponentMock()
    properties.setValue(KEY_PREFIX + OUTER_GROUP_NAME, true, OUTER_EXPANDED_BY_DEFAULT)
    properties.setValue(KEY_PREFIX + INNER_GROUP_NAME, true, INNER_EXPANDED_BY_DEFAULT)
    val test = Labels(properties)
    assertThat(test.outerGroup.expanded).isTrue()
    assertThat(test.innerGroup.expanded).isTrue()
    assertThat(test.colorItem.visible).isTrue()
    assertThat(test.textItem.visible).isTrue()
  }

  @Test
  fun testInitialCollapsedStateIsReadFromProperties() {
    val properties = PropertiesComponentMock()
    properties.setValue(KEY_PREFIX + OUTER_GROUP_NAME, false, OUTER_EXPANDED_BY_DEFAULT)
    properties.setValue(KEY_PREFIX + INNER_GROUP_NAME, false, INNER_EXPANDED_BY_DEFAULT)
    val test = Labels(properties)
    assertThat(test.outerGroup.expanded).isFalse()
    assertThat(test.innerGroup.expanded).isFalse()
    assertThat(test.colorItem.visible).isFalse()
    assertThat(test.textItem.visible).isFalse()
  }

  @Test
  fun testInitialOuterCollapsedInnerExpandedStateIsReadFromProperties() {
    val properties = PropertiesComponentMock()
    properties.setValue(KEY_PREFIX + OUTER_GROUP_NAME, false, OUTER_EXPANDED_BY_DEFAULT)
    properties.setValue(KEY_PREFIX + INNER_GROUP_NAME, true, INNER_EXPANDED_BY_DEFAULT)
    val test = Labels(properties)
    assertThat(test.outerGroup.expanded).isFalse()
    assertThat(test.outerGroup.expanded).isFalse()
    assertThat(test.colorItem.visible).isFalse()
    assertThat(test.textItem.visible).isFalse()
  }

  @Test
  fun testHiddenIsPropagated() {
    val test = Labels()
    test.innerGroup.hidden = true
    assertThat(test.backgroundTintItem.hidden).isTrue()
    assertThat(test.textItem.hidden).isTrue()
  }

  @Test
  fun testLabelWithoutEditorIsNotAMatch() {
    val test = Labels()
    assertThat(test.outerGroup.isMatch(Matcher { it.startsWith("Outer") })).isFalse()
  }
}
