// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package software.aws.toolkits.jetbrains.services.lambda.dotnet
import com.intellij.ui.ColorUtil
import com.intellij.ui.components.JBScrollPane
import com.intellij.ui.components.JBTabbedPane
import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil
import com.intellij.xml.util.XmlUtil
import com.jetbrains.rider.ideaInterop.fileTypes.sln.SolutionFileType
import com.jetbrains.rider.projectView.actions.projectTemplating.backend.ReSharperTemplateGeneratorBase
import com.jetbrains.rider.projectView.actions.projectTemplating.impl.ProjectTemplateDialogContext
import com.jetbrains.rider.projectView.actions.projectTemplating.impl.ProjectTemplateTransferableModel
import com.jetbrains.rider.ui.themes.RiderTheme
import software.aws.toolkits.jetbrains.services.lambda.BuiltInRuntimeGroups
import software.aws.toolkits.jetbrains.services.lambda.RuntimeGroup
import software.aws.toolkits.jetbrains.services.lambda.wizard.SamInitSelectionPanel
import software.aws.toolkits.jetbrains.services.lambda.wizard.SamProjectGenerator
import software.aws.toolkits.jetbrains.utils.DotNetRuntimeUtils
import software.aws.toolkits.resources.message
import java.awt.Dimension
import java.io.File
import javax.swing.JScrollPane
import javax.swing.JTabbedPane
import javax.swing.JTextPane
abstract class DotNetSamProjectGeneratorRoot(
private val context: ProjectTemplateDialogContext,
group: String,
categoryName: String,
model: ProjectTemplateTransferableModel
) : ReSharperTemplateGeneratorBase(
model = model,
createSolution = true,
createProject = true,
item = context.entity
) {
companion object {
private const val SAM_HELLO_WORLD_PROJECT_NAME = "HelloWorld"
}
// TODO: Decouple SamProjectGenerator from the framework wizards so we can re-use its panels
private val generator = SamProjectGenerator()
private val samPanel = SamInitSelectionPanel(
generator.wizardFragments,
// Only show templates for DotNet in Rider
runtimeFilter = { RuntimeGroup.getById(BuiltInRuntimeGroups.Dotnet).supportedRuntimes.contains(it) },
// needed to rerun the validation when the wizard is changed
wizardUpdateCallback = { validateData() }
)
fun getSamPanel() = samPanel
fun getSamGenerator() = generator
private val projectStructurePanel: JTabbedPane
private val structurePane = JTextPane().apply {
contentType = "text/html"
isEditable = false
background = RiderTheme.activeFieldBackground
border = null
}
init {
title.labels = arrayOf(group, categoryName)
initProjectTextField()
initSamPanel()
projectStructurePanel = JBTabbedPane()
val structureScroll = JBScrollPane(structurePane).apply {
horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
verticalScrollBarPolicy = JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
border = JBUI.Borders.empty()
background = UIUtil.getTextFieldBackground()
preferredSize = Dimension(1, JBUI.scale(60))
}
projectStructurePanel.add("Resulting project structure", structureScroll)
updateInfo()
super.initialize()
super.layout()
// Call this init method after super.initialize() to make sure solutionNameField override a base listener
initSolutionTextField()
addAdditionPane(samPanel.mainPanel)
addAdditionPane(projectStructurePanel)
}
override fun validateData() {
super.validateData()
if (validationError.value != null) {
return
}
samPanel.validate()?.let {
validationError.set(it.message)
return
}
validationError.set(null)
}
override fun updateInfo() {
super.updateInfo()
val sep = File.separator
val builder = StringBuilder()
val font = JBUI.Fonts.label()
builder.appendLine("")
if (solutionDirectory != null && solutionDirectory != projectDirectory) {
builder.appendLine(htmlText(parentStr, "${solutionDirectory.name}${sep}src$sep${projectDirectory.name}$sep$projectFilesLabel"))
builder.appendLine(htmlText(parentStr, "${solutionDirectory.name}${sep}test$sep${projectDirectory.name}.Test$sep$projectFilesLabel"))
} else {
builder.appendLine(htmlText(parentStr, "src$sep${projectDirectory.name}$sep$projectFilesLabel"))
builder.appendLine(htmlText(parentStr, "test$sep${projectDirectory.name}.Test$sep$projectFilesLabel"))
}
}
builder.appendLine("")
structurePane.text = builder.toString()
validateData()
}
override fun refreshUI() {
super.refreshUI()
// This restore project name when user change a solution name and switch between templates
projectNameField.text = SAM_HELLO_WORLD_PROJECT_NAME
validationError.set(null)
validateData()
}
private fun initSolutionTextField() {
solutionNameField.text = getPossibleName(SAM_HELLO_WORLD_PROJECT_NAME)
}
/**
* The project name is generated inside SAM CLI generator and cannot be re-defined via parameters.
* Hardcode the project name to the generated one - "HelloWorld".
*/
private fun initProjectTextField() {
projectNameField.text = SAM_HELLO_WORLD_PROJECT_NAME
projectNameField.isEnabled = false
projectNameSetByUser = true
sameDirectoryCheckBox.isEnabled = false
}
private fun initSamPanel() {
samPanel.setRuntime(DotNetRuntimeUtils.getCurrentDotNetCoreRuntime())
}
private fun htmlText(baseDir: String, relativePath: String) =
"...$baseDir$relativePath
"
}