---
title: "Interactive Biomechanical Data Dashboard"
output: 
  flexdashboard::flex_dashboard:
    theme: flatly
    orientation: rows
    vertical_layout: fill
    social: menu
    source_code: embed
params:
  dataset: "gait_data.parquet"
  control_dataset: "control_data.parquet"  # optional comparison group
  subject_filter: "all"  # "all" or specific subject ID
  task_filter: "all"     # "all" or specific task
  real_time_mode: FALSE
  dashboard_title: "Biomechanical Analysis Dashboard"
runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(LocomotionData)
library(plotly)
library(DT)
library(dplyr)
library(viridis)
library(crosstalk)

# Load data
if (file.exists(params$dataset)) {
  main_data <- loadLocomotionData(params$dataset)
  subjects <- getSubjects(main_data)
  tasks <- getTasks(main_data)
  features <- getFeatures(main_data)
} else {
  stop("Dataset not found: ", params$dataset)
}

# Load control data if available
control_data <- NULL
if (!is.null(params$control_dataset) && 
    params$control_dataset != "" && 
    file.exists(params$control_dataset)) {
  control_data <- loadLocomotionData(params$control_dataset)
}

# Key biomechanical features
key_features <- intersect(c(
  "knee_flexion_angle_ipsi_rad", "knee_flexion_angle_contra_rad",
  "hip_flexion_angle_ipsi_rad", "hip_flexion_angle_contra_rad",
  "ankle_flexion_angle_ipsi_rad", "ankle_flexion_angle_contra_rad"
), features)

# Initialize reactive values
phase_vector <- seq(0, 100, length.out = 150)
```

Sidebar {.sidebar}
=====================================

### Data Controls

```{r}
# Subject selection
selectInput("selected_subject", 
            "Select Subject:",
            choices = c("All" = "all", setNames(subjects, subjects)),
            selected = if (params$subject_filter != "all") params$subject_filter else "all")

# Task selection  
selectInput("selected_task",
            "Select Task:",
            choices = c("All" = "all", setNames(tasks, tasks)),
            selected = if (params$task_filter != "all") params$task_filter else "all")

# Feature selection for detailed analysis
selectInput("selected_features",
            "Select Features:",
            choices = setNames(key_features, gsub("_", " ", key_features)),
            selected = key_features[1:3],
            multiple = TRUE)
```

### Analysis Options

```{r}
# Comparison options
checkboxInput("show_control", "Show Control Group", 
              value = !is.null(control_data))

checkboxInput("show_individual", "Show Individual Cycles", value = FALSE)

checkboxInput("show_statistics", "Show Statistics", value = TRUE)

# Plot customization
sliderInput("plot_alpha", "Line Transparency:", 
            min = 0.1, max = 1.0, value = 0.8, step = 0.1)

selectInput("color_scheme", "Color Scheme:",
            choices = c("Viridis" = "viridis", "Plasma" = "plasma", 
                       "Inferno" = "inferno", "Magma" = "magma"),
            selected = "viridis")
```

### Data Summary

```{r}
renderValueBox({
  valueBox(
    value = length(subjects),
    caption = "Total Subjects",
    icon = "fa-users",
    color = "primary"
  )
})

renderValueBox({
  valueBox(
    value = length(tasks),
    caption = "Tasks Available", 
    icon = "fa-walking",
    color = "info"
  )
})

renderValueBox({
  valueBox(
    value = length(features),
    caption = "Features Available",
    icon = "fa-chart-line", 
    color = "success"
  )
})
```

Row {data-height=600}
=====================================

### **Primary Analysis** {.tabset}

#### Gait Patterns

```{r}
renderPlotly({
  # Get current selections
  current_subject <- input$selected_subject
  current_task <- input$selected_task
  current_features <- input$selected_features
  
  if (is.null(current_features) || length(current_features) == 0) {
    return(NULL)
  }
  
  # Prepare plot data
  plot_data <- data.frame()
  
  if (current_subject == "all") {
    # Group analysis - show mean patterns
    for (subj in subjects[1:min(5, length(subjects))]) {  # Limit for performance
      for (task in if (current_task == "all") tasks else current_task) {
        mean_patterns <- getMeanPatterns(main_data, subj, task, current_features)
        
        for (feature in current_features) {
          if (feature %in% names(mean_patterns)) {
            feature_data <- data.frame(
              Phase = phase_vector,
              Value = mean_patterns[[feature]] * 180/pi,
              Subject = subj,
              Task = task,
              Feature = gsub("_", " ", feature)
            )
            plot_data <- rbind(plot_data, feature_data)
          }
        }
      }
    }
  } else {
    # Single subject analysis
    for (task in if (current_task == "all") tasks else current_task) {
      if (input$show_individual) {
        # Show individual cycles
        cycles_result <- getCycles(main_data, current_subject, task, current_features)
        if (!is.null(cycles_result)) {
          data_3d <- cycles_result$data_3d
          
          for (i in seq_along(current_features)) {
            feature <- current_features[i]
            if (i <= dim(data_3d)[3]) {
              for (cycle in 1:min(10, dim(data_3d)[1])) {  # Limit cycles for performance
                cycle_data <- data.frame(
                  Phase = phase_vector,
                  Value = data_3d[cycle, , i] * 180/pi,
                  Subject = paste(current_subject, "Cycle", cycle),
                  Task = task,
                  Feature = gsub("_", " ", feature)
                )
                plot_data <- rbind(plot_data, cycle_data)
              }
            }
          }
        }
      } else {
        # Show mean pattern
        mean_patterns <- getMeanPatterns(main_data, current_subject, task, current_features)
        
        for (feature in current_features) {
          if (feature %in% names(mean_patterns)) {
            feature_data <- data.frame(
              Phase = phase_vector,
              Value = mean_patterns[[feature]] * 180/pi,
              Subject = current_subject,
              Task = task,
              Feature = gsub("_", " ", feature)
            )
            plot_data <- rbind(plot_data, feature_data)
          }
        }
      }
    }
  }
  
  if (nrow(plot_data) == 0) {
    return(plotly_empty())
  }
  
  # Create interactive plot
  p <- plot_ly(data = plot_data,
               x = ~Phase, y = ~Value,
               color = ~Feature,
               linetype = ~Task,
               type = 'scatter', mode = 'lines',
               alpha = input$plot_alpha,
               hovertemplate = paste(
                 "<b>%{fullData.name}</b><br>",
                 "Phase: %{x}%<br>",
                 "Angle: %{y:.1f}°<br>",
                 "Subject: %{text}<br>",
                 "<extra></extra>"
               ),
               text = ~Subject) %>%
    layout(
      title = list(text = "Gait Pattern Analysis", font = list(size = 16)),
      xaxis = list(title = "Gait Cycle (%)"),
      yaxis = list(title = "Joint Angle (degrees)"),
      hovermode = "x unified",
      legend = list(orientation = "h", y = -0.1)
    ) %>%
    colorbar(title = "Feature")
  
  p
})
```

#### Comparison View

```{r}
renderPlotly({
  if (!input$show_control || is.null(control_data)) {
    return(plotly_empty() %>% 
           layout(title = "Control data not available"))
  }
  
  current_task <- if (input$selected_task == "all") tasks[1] else input$selected_task
  current_feature <- if (length(input$selected_features) > 0) input$selected_features[1] else key_features[1]
  
  # Get main data pattern
  if (input$selected_subject == "all") {
    # Group mean
    main_subjects <- subjects[1:min(10, length(subjects))]
    main_patterns <- sapply(main_subjects, function(s) {
      getMeanPatterns(main_data, s, current_task, current_feature)[[1]]
    })
    main_mean <- rowMeans(main_patterns, na.rm = TRUE) * 180/pi
  } else {
    main_mean <- getMeanPatterns(main_data, input$selected_subject, current_task, current_feature)[[1]] * 180/pi
  }
  
  # Get control data pattern
  control_subjects <- getSubjects(control_data)
  control_patterns <- sapply(control_subjects[1:min(10, length(control_subjects))], function(s) {
    getMeanPatterns(control_data, s, current_task, current_feature)[[1]]
  })
  control_mean <- rowMeans(control_patterns, na.rm = TRUE) * 180/pi
  
  # Create comparison plot
  comparison_data <- data.frame(
    Phase = rep(phase_vector, 2),
    Value = c(main_mean, control_mean),
    Group = rep(c("Study Group", "Control Group"), each = 150)
  )
  
  p <- plot_ly(data = comparison_data,
               x = ~Phase, y = ~Value,
               color = ~Group,
               type = 'scatter', mode = 'lines',
               line = list(width = 3),
               hovertemplate = paste(
                 "<b>%{fullData.name}</b><br>",
                 "Phase: %{x}%<br>",
                 "Angle: %{y:.1f}°<br>",
                 "<extra></extra>"
               )) %>%
    layout(
      title = list(text = paste("Group Comparison:", gsub("_", " ", current_feature)), 
                   font = list(size = 16)),
      xaxis = list(title = "Gait Cycle (%)"),
      yaxis = list(title = "Joint Angle (degrees)"),
      hovermode = "x unified"
    )
  
  p
})
```

#### 3D Trajectory

```{r}
renderPlotly({
  if (length(input$selected_features) < 3) {
    return(plotly_empty() %>%
           layout(title = "Select at least 3 features for 3D visualization"))
  }
  
  current_subject <- if (input$selected_subject == "all") subjects[1] else input$selected_subject
  current_task <- if (input$selected_task == "all") tasks[1] else input$selected_task
  selected_3_features <- input$selected_features[1:3]
  
  # Get mean patterns for 3D plot
  mean_patterns <- getMeanPatterns(main_data, current_subject, current_task, selected_3_features)
  
  if (length(mean_patterns) >= 3) {
    plot_data_3d <- data.frame(
      Phase = phase_vector,
      X = mean_patterns[[1]] * 180/pi,
      Y = mean_patterns[[2]] * 180/pi,
      Z = mean_patterns[[3]] * 180/pi
    )
    
    p_3d <- plot_ly(data = plot_data_3d,
                    x = ~X, y = ~Y, z = ~Z,
                    type = 'scatter3d', mode = 'lines+markers',
                    line = list(width = 6, color = ~Phase, colorscale = input$color_scheme),
                    marker = list(size = 4, color = ~Phase, colorscale = input$color_scheme),
                    hovertemplate = paste(
                      "Phase: %{text}%<br>",
                      gsub("_", " ", selected_3_features[1]), ": %{x:.1f}°<br>",
                      gsub("_", " ", selected_3_features[2]), ": %{y:.1f}°<br>",
                      gsub("_", " ", selected_3_features[3]), ": %{z:.1f}°<br>",
                      "<extra></extra>"
                    ),
                    text = ~Phase) %>%
      layout(
        title = list(text = "3D Gait Trajectory", font = list(size = 16)),
        scene = list(
          xaxis = list(title = gsub("_", " ", selected_3_features[1])),
          yaxis = list(title = gsub("_", " ", selected_3_features[2])),
          zaxis = list(title = gsub("_", " ", selected_3_features[3]))
        )
      )
    
    p_3d
  } else {
    plotly_empty()
  }
})
```

Row {data-height=400}
=====================================

### **Range of Motion Analysis**

```{r}
renderPlotly({
  current_subject <- input$selected_subject
  current_task <- input$selected_task
  current_features <- input$selected_features
  
  if (is.null(current_features) || length(current_features) == 0) {
    return(NULL)
  }
  
  # Calculate ROM data
  rom_data <- data.frame()
  
  if (current_subject == "all") {
    # Multiple subjects
    for (subj in subjects) {
      for (task in if (current_task == "all") tasks else current_task) {
        rom_results <- calculateROM(main_data, subj, task, current_features, by_cycle = FALSE)
        
        for (feature in names(rom_results)) {
          if (feature %in% current_features) {
            rom_row <- data.frame(
              Subject = subj,
              Task = task,
              Feature = gsub("_", " ", feature),
              ROM = rom_results[[feature]] * 180/pi
            )
            rom_data <- rbind(rom_data, rom_row)
          }
        }
      }
    }
  } else {
    # Single subject
    for (task in if (current_task == "all") tasks else current_task) {
      rom_results <- calculateROM(main_data, current_subject, task, current_features, by_cycle = FALSE)
      
      for (feature in names(rom_results)) {
        if (feature %in% current_features) {
          rom_row <- data.frame(
            Subject = current_subject,
            Task = task,
            Feature = gsub("_", " ", feature),
            ROM = rom_results[[feature]] * 180/pi
          )
          rom_data <- rbind(rom_data, rom_row)
        }
      }
    }
  }
  
  if (nrow(rom_data) == 0) {
    return(plotly_empty())
  }
  
  # Create ROM bar plot
  p_rom <- plot_ly(data = rom_data,
                   x = ~Feature, y = ~ROM,
                   color = ~Task,
                   type = 'bar',
                   hovertemplate = paste(
                     "<b>%{fullData.name}</b><br>",
                     "Feature: %{x}<br>",
                     "ROM: %{y:.1f}°<br>",
                     "Subject: %{text}<br>",
                     "<extra></extra>"
                   ),
                   text = ~Subject) %>%
    layout(
      title = list(text = "Range of Motion Analysis", font = list(size = 14)),
      xaxis = list(title = "Feature"),
      yaxis = list(title = "ROM (degrees)"),
      barmode = 'group'
    )
  
  p_rom
})
```

### **Quality Metrics**

```{r}
renderPlotly({
  current_subject <- input$selected_subject
  current_task <- input$selected_task
  
  # Calculate data quality metrics
  quality_data <- data.frame()
  
  subjects_to_analyze <- if (current_subject == "all") subjects[1:min(10, length(subjects))] else current_subject
  tasks_to_analyze <- if (current_task == "all") tasks else current_task
  
  for (subj in subjects_to_analyze) {
    for (task in tasks_to_analyze) {
      # Validate cycles
      valid_mask <- validateCycles(main_data, subj, task)
      
      quality_row <- data.frame(
        Subject = subj,
        Task = task,
        Total_Cycles = length(valid_mask),
        Valid_Cycles = sum(valid_mask),
        Validity_Rate = sum(valid_mask) / length(valid_mask) * 100
      )
      quality_data <- rbind(quality_data, quality_row)
    }
  }
  
  if (nrow(quality_data) == 0) {
    return(plotly_empty())
  }
  
  # Create quality heatmap
  p_quality <- plot_ly(data = quality_data,
                       x = ~Task, y = ~Subject,
                       z = ~Validity_Rate,
                       type = 'heatmap',
                       colorscale = list(c(0, "red"), c(0.5, "yellow"), c(1, "green")),
                       hovertemplate = paste(
                         "Subject: %{y}<br>",
                         "Task: %{x}<br>",
                         "Validity: %{z:.1f}%<br>",
                         "Valid Cycles: %{text}<br>",
                         "<extra></extra>"
                       ),
                       text = ~paste(Valid_Cycles, "/", Total_Cycles)) %>%
    layout(
      title = list(text = "Data Quality Heatmap", font = list(size = 14)),
      xaxis = list(title = "Task"),
      yaxis = list(title = "Subject")
    ) %>%
    colorbar(title = "Validity Rate (%)")
  
  p_quality
})
```

Row {data-height=300}
=====================================

### **Data Table** {.tabset}

#### Summary Statistics

```{r}
renderDT({
  if (!input$show_statistics) {
    return(NULL)
  }
  
  current_subject <- input$selected_subject
  current_task <- input$selected_task
  current_features <- input$selected_features
  
  if (is.null(current_features) || length(current_features) == 0) {
    return(NULL)
  }
  
  # Calculate summary statistics
  stats_data <- data.frame()
  
  subjects_to_analyze <- if (current_subject == "all") subjects[1:min(5, length(subjects))] else current_subject
  tasks_to_analyze <- if (current_task == "all") tasks else current_task
  
  for (subj in subjects_to_analyze) {
    for (task in tasks_to_analyze) {
      stats_results <- getSummaryStatistics(main_data, subj, task, current_features)
      
      for (feature in names(stats_results)) {
        if (feature %in% current_features) {
          stats_row <- data.frame(
            Subject = subj,
            Task = task,
            Feature = gsub("_", " ", feature),
            Mean = round(stats_results[[feature]]$mean * 180/pi, 2),
            SD = round(stats_results[[feature]]$sd * 180/pi, 2),
            Min = round(stats_results[[feature]]$min * 180/pi, 2),
            Max = round(stats_results[[feature]]$max * 180/pi, 2),
            ROM = round((stats_results[[feature]]$max - stats_results[[feature]]$min) * 180/pi, 2)
          )
          stats_data <- rbind(stats_data, stats_row)
        }
      }
    }
  }
  
  if (nrow(stats_data) > 0) {
    datatable(stats_data,
              options = list(pageLength = 10, scrollX = TRUE),
              rownames = FALSE) %>%
      formatRound(columns = c("Mean", "SD", "Min", "Max", "ROM"), digits = 2)
  }
})
```

#### Raw Data Preview

```{r}
renderDT({
  # Show a preview of the raw data structure
  if (input$selected_subject != "all" && input$selected_task != "all") {
    # Get cycles data for preview
    cycles_result <- getCycles(main_data, input$selected_subject, input$selected_task, 
                              input$selected_features[1:min(3, length(input$selected_features))])
    
    if (!is.null(cycles_result)) {
      data_3d <- cycles_result$data_3d
      
      # Convert to data frame for display (first cycle, all phases)
      if (dim(data_3d)[1] > 0) {
        preview_data <- data.frame(
          Phase = phase_vector,
          Cycle_1_Feature_1 = round(data_3d[1, , 1] * 180/pi, 2)
        )
        
        if (dim(data_3d)[3] > 1) {
          preview_data$Cycle_1_Feature_2 <- round(data_3d[1, , 2] * 180/pi, 2)
        }
        
        if (dim(data_3d)[3] > 2) {
          preview_data$Cycle_1_Feature_3 <- round(data_3d[1, , 3] * 180/pi, 2)
        }
        
        # Rename columns with actual feature names
        feature_names <- cycles_result$feature_names[1:min(3, length(cycles_result$feature_names))]
        if (length(feature_names) >= 1) {
          names(preview_data)[2] <- gsub("_", " ", feature_names[1])
        }
        if (length(feature_names) >= 2) {
          names(preview_data)[3] <- gsub("_", " ", feature_names[2])
        }
        if (length(feature_names) >= 3) {
          names(preview_data)[4] <- gsub("_", " ", feature_names[3])
        }
        
        datatable(preview_data,
                  options = list(pageLength = 15, scrollY = "200px"),
                  caption = paste("First Cycle Data for", input$selected_subject, "-", input$selected_task),
                  rownames = FALSE) %>%
          formatRound(columns = 2:ncol(preview_data), digits = 2)
      }
    }
  } else {
    # Show message when specific subject/task not selected
    data.frame(
      Message = "Select a specific subject and task to view raw cycle data"
    ) %>%
    datatable(options = list(dom = 't'), rownames = FALSE)
  }
})
```

### **Export Options**

```{r}
fluidRow(
  column(4,
    downloadButton("download_plot", "Download Current Plot", 
                   class = "btn-primary btn-sm")),
  column(4,
    downloadButton("download_data", "Download Data", 
                   class = "btn-success btn-sm")),
  column(4,
    actionButton("refresh_data", "Refresh Dashboard", 
                 class = "btn-info btn-sm"))
)

# Download handlers
output$download_plot <- downloadHandler(
  filename = function() {
    paste("gait_analysis_plot_", Sys.Date(), ".png", sep = "")
  },
  content = function(file) {
    # Export current plot (simplified - would need to track current plot)
    ggsave(file, plot = last_plot(), width = 12, height = 8, dpi = 300)
  }
)

output$download_data <- downloadHandler(
  filename = function() {
    paste("gait_analysis_data_", Sys.Date(), ".csv", sep = "")
  },
  content = function(file) {
    # Export summary data based on current selections
    if (input$show_statistics && input$selected_subject != "all") {
      stats_results <- getSummaryStatistics(main_data, input$selected_subject, 
                                           input$selected_task, input$selected_features)
      write.csv(stats_results, file, row.names = FALSE)
    }
  }
)

observeEvent(input$refresh_data, {
  # Refresh reactive values
  showNotification("Dashboard refreshed!", type = "message")
})
```

About
=====================================

### Dashboard Information

**Interactive Biomechanical Data Dashboard**

This dashboard provides real-time interactive analysis of biomechanical gait data using the LocomotionData R package. Features include:

#### **Key Capabilities**
- **Real-time filtering** by subjects and tasks
- **Interactive 2D and 3D visualizations** with hover details
- **Dynamic comparison** between study and control groups  
- **Quality assessment** metrics and validation
- **Export functionality** for plots and data

#### **Visualization Features**
- **Gait Patterns:** Phase-normalized joint angle trajectories
- **3D Trajectories:** Multi-dimensional movement patterns
- **Range of Motion:** Comparative ROM analysis
- **Quality Metrics:** Data validation and reliability assessment

#### **Technical Details**
- **Data Format:** Phase-indexed biomechanical data (150 points per cycle)
- **Interactivity:** Powered by Plotly and Shiny
- **Real-time Updates:** Dynamic filtering and visualization
- **Export Options:** PNG plots and CSV data downloads

#### **Usage Instructions**
1. **Select Data:** Use sidebar controls to filter subjects and tasks
2. **Choose Features:** Select specific biomechanical variables for analysis
3. **Interact:** Hover over plots for detailed information
4. **Compare:** Enable control group comparison if available
5. **Export:** Download plots and data for further analysis

#### **Data Requirements**
- Standard LocomotionData format
- Phase-indexed data with exactly 150 points per gait cycle
- Required columns: subject, task, phase
- Optional: control group dataset for comparison

**Powered by:** LocomotionData R Package, Plotly, Flexdashboard