---
title: "Getting Started with PhysioCore"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with PhysioCore}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

## Introduction

PhysioCore provides the `PhysioExperiment` class, a Bioconductor-compatible
data structure for multi-modal physiological signal data. Built on top of
`SummarizedExperiment`, it adds a sampling rate slot and convenience
functions for channel management, event handling, and signal utilities.

This vignette covers the basics of creating `PhysioExperiment` objects,
accessing and modifying their contents, and managing channel metadata.

## Creating a PhysioExperiment

The `PhysioExperiment()` constructor accepts assay data (as a list of
matrices or arrays), channel metadata via `colData`, and a sampling rate
in Hz.

```{r create-basic, eval=FALSE}
library(PhysioCore)

# Simulate 4 seconds of 4-channel EEG data at 250 Hz
n_time <- 1000
n_channels <- 4
sr <- 250

eeg_data <- matrix(rnorm(n_time * n_channels), nrow = n_time, ncol = n_channels)

pe <- PhysioExperiment(
  assays = list(raw = eeg_data),
  colData = S4Vectors::DataFrame(
    label = c("Fz", "Cz", "Pz", "Oz"),
    type = rep("EEG", n_channels)
  ),
  samplingRate = sr
)

pe
```

### Multiple Assays

You can store multiple processing stages as separate assays. For example,
a raw signal and a filtered version:

```{r multiple-assays, eval=FALSE}
pe_multi <- PhysioExperiment(
  assays = list(
    raw = eeg_data,
    filtered = eeg_data * 0.8  # placeholder for filtered data
  ),
  colData = S4Vectors::DataFrame(
    label = c("Fz", "Cz", "Pz", "Oz"),
    type = rep("EEG", n_channels)
  ),
  samplingRate = sr
)

SummarizedExperiment::assayNames(pe_multi)
```

## Accessing Basic Properties

### Sampling Rate

```{r sampling-rate, eval=FALSE}
# Get sampling rate
samplingRate(pe)

# Set sampling rate
samplingRate(pe) <- 500
samplingRate(pe)
```

### Dimensions and Duration

```{r dimensions, eval=FALSE}
# Number of time points x channels
dim(pe)

# Total number of time points
length(pe)

# Signal duration in seconds
duration(pe)

# Time vector in seconds
head(timeIndex(pe))
```

### Default Assay

The first assay is treated as the default for operations that do not
specify an assay explicitly:

```{r default-assay, eval=FALSE}
defaultAssay(pe)
```

## Channel Management

PhysioCore provides a rich set of functions for managing channel metadata.

### Reading Channel Information

```{r channel-info, eval=FALSE}
# Full channel metadata (returns a DataFrame)
channelInfo(pe)

# Channel labels
channelNames(pe)

# Number of channels
nChannels(pe)
```

### Setting Channel Properties

```{r channel-properties, eval=FALSE}
# Rename channels
channelNames(pe) <- c("F3", "C3", "P3", "O1")
channelNames(pe)

# Or rename specific channels
pe <- renameChannels(pe, old_names = "F3", new_names = "Fz")

# Set channel types
pe <- setChannelTypes(pe, c("EEG", "EEG", "EEG", "EEG"))

# Set channel types by name
pe <- setChannelTypes(pe, c(Fz = "EEG"))

# Set physical units
pe <- setChannelUnits(pe, "uV")
```

### Subsetting Channels

```{r channel-subsetting, eval=FALSE}
# Pick channels by name
pe_frontal <- pickChannels(pe, c("Fz", "C3"))
nChannels(pe_frontal)

# Pick channels by index
pe_subset <- pickChannels(pe, c(1, 3))

# Drop channels
pe_dropped <- dropChannels(pe, "O1")
nChannels(pe_dropped)

# Get channel indices by type
eeg_idx <- getChannelsByType(pe, "EEG")
```

### Electrode Positions and Montages

```{r electrode-positions, eval=FALSE}
# Apply a standard 10-20 montage
pe <- applyMontage(pe, "10-20")

# Read electrode positions
positions <- getElectrodePositions(pe)
head(positions)

# Set custom positions
custom_pos <- data.frame(
  x = c(0, 0, 0, 0),
  y = c(0.71, 0, -0.71, -1.0),
  z = c(0.71, 1.0, 0.71, 0)
)
pe <- setElectrodePositions(pe, custom_pos)
```

### Reference Electrode

```{r reference, eval=FALSE}
# Set the reference electrode
pe <- setReference(pe, "average")
getReference(pe)
```

## Subsetting and Combining

### Time-based Subsetting

```{r time-subsetting, eval=FALSE}
# Extract a time window (in seconds)
pe_window <- extractWindow(pe, tmin = 1.0, tmax = 3.0)
duration(pe_window)

# Index-based subsetting
pe_first50 <- pe[1:50, ]
dim(pe_first50)
```

### Combining Objects

```{r combining, eval=FALSE}
# Combine by channels (same time points required)
pe1 <- pickChannels(pe, c(1, 2))
pe2 <- pickChannels(pe, c(3, 4))
pe_combined <- cbindPhysio(pe1, pe2)
nChannels(pe_combined)

# Combine by time (same channels required)
pe_first <- pe[1:500, ]
pe_second <- pe[501:1000, ]
pe_concat <- rbindPhysio(pe_first, pe_second)
length(pe_concat)
```

## Summary Statistics

```{r summary, eval=FALSE}
# Per-channel summary statistics
summary(pe)

# Convert to data.frame for further analysis
df <- as.data.frame(pe)
head(df)
```

## NA Handling

PhysioCore provides utilities for checking and handling missing values:
```{r na-handling, eval=FALSE}
# Check for NA presence
hasNA(pe)

# Detailed NA check
checkNA(pe)

# NA summary across all assays
naSummary(pe)

# Replace NA values in an assay
pe_clean <- replaceNA(pe, method = "interpolate")

# Handle NA in a numeric vector
x <- c(1, NA, 3, NA, 5)
handleNA(x, method = "interpolate")
handleNA(x, method = "locf")

# Fill edge NA values
y <- c(NA, NA, 1, 2, 3, NA)
fillEdgeNA(y, method = "extend")
```

## Next Steps

- See `vignette("event-handling", package = "PhysioCore")` for working with
  experimental events and triggers.
- Explore the PhysioAnalysis, PhysioPreprocess, and PhysioIO packages for
  signal processing, filtering, and file I/O capabilities built on
  PhysioCore.

## Session Info

```{r session-info, eval=FALSE}
sessionInfo()
```
