# YSP Hex Printing Functionality

## Overview

The YSP hex printing functionality provides comprehensive tools for displaying YSP messages in hexadecimal format with proper length and header breakdown. This is essential for debugging, logging, and verification of YSP packet structure.

## Key Features

### 1. **Multiple Output Formats**
- **Compact**: Single line hex output
- **Detailed**: Multi-line breakdown with labels
- **Breakdown**: Complete analysis with validation

### 2. **Flexible Input Types**
- Raw ISO data (automatically frames with YSP header)
- Complete framed YSP packets (analyzes existing structure)
- ISO message objects (packs and frames)

### 3. **Output Options**
- Console output (default)
- String return for programmatic use

## Usage Examples

### Basic Hex Printing

```elixir
# Print ISO data with YSP framing
iso_data = "sample_iso_data"
YspMessageFraming.print_hex_with_header(iso_data)

# Output:
# YSP Message Hex Format:
# ========================
# Length: 0013 (19 bytes total)
# Header: 3022 (YSP ADR + CB ON)
# ISO Data: 73616D706C655F69736F5F64617461 (15 bytes)
# ========================
# Complete: 00133022 73616D706C655F69736F5F64617461
```

### Analyze Framed Packets

```elixir
# Analyze complete YSP packet
sample_hex = "0245302260007820000200703c278028c0..."
packet = Base.decode16!(sample_hex)
YspMessageFraming.print_hex_with_header(packet, type: :framed_packet, format: :breakdown)

# Output:
# YSP Framed Packet Breakdown:
# ============================
# [Length: 0245] [Header: 3022] [ISO Data: 00 07 82 00 02 ...]
# 
# Analysis:
# - Declared Length: 581 bytes (0x0245)
# - Actual Length: 581 bytes
# - YSP Header: 0x3022 (✓ Valid)
# - ISO Data Length: 577 bytes
# - Validation: valid
```

### Process with Debug Output

```elixir
# Process message with automatic hex printing
YspProcessor.process_with_hex_debug(iso_message, context)

# Prints both request and response in hex format
# with ISO field breakdown
```

## API Reference

### YspMessageFraming Module

#### `print_hex_with_header/2`

```elixir
YspMessageFraming.print_hex_with_header(data, opts \\ [])
```

**Parameters:**
- `data`: Binary data (ISO data or framed packet)
- `opts`: Options
  - `:type` - `:iso_data` (default) or `:framed_packet`
  - `:format` - `:compact`, `:detailed` (default), or `:breakdown`
  - `:output` - `:console` (default) or `:string`

**Returns:**
- `:ok` when printing to console
- String when `:output` is `:string`

#### `format_iso_data_hex/2`

```elixir
YspMessageFraming.format_iso_data_hex(iso_data, format \\ :detailed)
```

Creates formatted hex string for ISO data with YSP framing.

#### `format_framed_packet_hex/2`

```elixir
YspMessageFraming.format_framed_packet_hex(packet, format \\ :detailed)
```

Analyzes and formats existing YSP framed packets.

#### `demo_hex_printing/0`

```elixir
YspMessageFraming.demo_hex_printing()
```

Built-in demonstration of all hex printing formats.

### YspProcessor Module

#### `print_message_hex/3`

```elixir
YspProcessor.print_message_hex(message, label \\ "YSP Message", opts \\ [])
```

Convenience function that supports:
- `ISOMsg` objects (includes field breakdown)
- Binary data
- Error handling for unsupported types

#### `process_with_hex_debug/3`

```elixir
YspProcessor.process_with_hex_debug(message, context \\ %{}, opts \\ [])
```

Processes message with automatic hex printing for debugging.

**Options:**
- `:print_request` - Print incoming message (default: true)
- `:print_response` - Print outgoing message (default: true)
- `:print_errors` - Print error details (default: true)

## Format Examples

### Compact Format
```
000A3022 74657374
```
- Length (000A) + Header (3022) + ISO Data (74657374)

### Detailed Format
```
YSP Message Hex Format:
========================
Length: 000A (10 bytes total)
Header: 3022 (YSP ADR + CB ON)
ISO Data: 74657374 (4 bytes)
========================
Complete: 000A3022 74657374
```

### Breakdown Format
```
YSP Message Breakdown:
=====================
[Length: 000A] [Header: 3022] [ISO Data: 74 65 73 74]

Details:
- Total Length: 10 bytes (0x000A)
- YSP Header: 0x3022 (ADR + CB ON)
- ISO Data Length: 4 bytes
- ISO Data Hex: 74657374

Raw Packet: 000A302274657374
```

## Quick Start Examples

### Using the Quick Start Module

```elixir
# Run all demos
DaProductApp.Acquirer.YSP.HexPrintingQuickStart.run_all_demos()

# Quick demo with sample data
DaProductApp.Acquirer.YSP.HexPrintingQuickStart.quick_demo()

# Analyze any hex string
DaProductApp.Acquirer.YSP.HexPrintingQuickStart.analyze_hex("000A302274657374")
```

### Integration in Your Code

```elixir
# In message processing
defp log_message_hex(message, label) do
  if Application.get_env(:da_product_app, :debug_hex_output, false) do
    YspProcessor.print_message_hex(message, label, format: :compact)
  end
end

# In network layer
defp log_packet(packet_data, direction) do
  YspMessageFraming.print_hex_with_header(
    packet_data, 
    type: :framed_packet, 
    format: :detailed
  )
end
```

## Configuration

### Environment Variables

```elixir
# In config/dev.exs or config/prod.exs
config :da_product_app,
  debug_hex_output: true,  # Enable hex printing in logs
  hex_format: :breakdown   # Default format for debug output
```

### Runtime Configuration

```elixir
# Check if hex output is enabled
if Application.get_env(:da_product_app, :debug_hex_output, false) do
  YspProcessor.print_message_hex(message, "Debug Message")
end
```

## Testing

The hex printing functionality includes comprehensive tests:

```bash
# Run YSP framing tests (includes hex printing tests)
mix test test/da_product_app/acquirer/ysp/ysp_message_framing_test.exs

# Run specific hex printing tests
mix test test/da_product_app/acquirer/ysp/ysp_message_framing_test.exs -t hex_printing
```

## Performance Considerations

- **Hex conversion**: Efficient binary-to-hex conversion using `Base.encode16/1`
- **Memory usage**: String formatting only occurs when printing is requested
- **Debug mode**: Can be disabled in production to avoid performance impact
- **Large packets**: Automatically handles packets up to 64KB

## Error Handling

The hex printing functions handle various error conditions:

```elixir
# Invalid packet structure
YspMessageFraming.print_hex_with_header(invalid_data, type: :framed_packet)
# Output includes error details and raw data

# Unsupported message types
YspProcessor.print_message_hex(unsupported_type, "Test")
# Output shows type information and raw data

# Malformed hex strings
HexPrintingQuickStart.analyze_hex("invalid_hex")
# Output: "❌ Invalid hex string: invalid_hex"
```

## Best Practices

1. **Use appropriate format for context**:
   - `:compact` for logs
   - `:detailed` for debugging
   - `:breakdown` for analysis

2. **Control output in production**:
   ```elixir
   if Mix.env() != :prod do
     YspProcessor.print_message_hex(message, "Debug")
   end
   ```

3. **Use string output for programmatic processing**:
   ```elixir
   hex_string = YspMessageFraming.print_hex_with_header(data, output: :string)
   Logger.info("Packet: #{hex_string}")
   ```

4. **Leverage built-in demos for learning**:
   ```elixir
   # Great for understanding the format
   YspMessageFraming.demo_hex_printing()
   ```

## Summary

The YSP hex printing functionality provides:

✅ **Complete packet visualization** with length and header breakdown  
✅ **Multiple output formats** for different use cases  
✅ **Integration with existing YSP processor** for seamless debugging  
✅ **Comprehensive error handling** for malformed data  
✅ **Performance optimized** with configurable output  
✅ **Extensive testing coverage** for reliability  

This functionality is essential for debugging YSP communication, verifying packet structure, and understanding message flow in the Mercury Device Middleware Layer.