pub fn calculate_xor_parity(data_stripes: &[Vec<u8>]) -> Vec<u8> {
    if data_stripes.is_empty() {
        return Vec::new();
    }
    
    let stripe_size = data_stripes[0].len();
    let mut parity = vec![0u8; stripe_size];
    
    for stripe in data_stripes {
        if stripe.len() != stripe_size {
            panic!("All stripes must have same size for parity calculation");
        }
        for i in 0..stripe_size {
            parity[i] ^= stripe[i];
        }
    }
    
    parity
}

pub fn reconstruct_missing_data(
    available_data: &[Vec<u8>],
    parity: &[u8],
    _missing_index: usize,
) -> Vec<u8> {
    if available_data.is_empty() || parity.is_empty() {
        return Vec::new();
    }
    
    let stripe_size = available_data[0].len();
    let mut reconstructed = parity.to_vec();
    
    for data in available_data.iter() {
        if data.len() != stripe_size {
            panic!("All data must have same size for reconstruction");
        }
        for i in 0..stripe_size {
            reconstructed[i] ^= data[i];
        }
    }
    
    reconstructed
}

pub fn calculate_new_parity(
    old_parity: &[u8],
    old_data: &[u8],
    new_data: &[u8],
) -> Vec<u8> {
    if old_parity.len() != old_data.len() || old_data.len() != new_data.len() {
        panic!("Parity and data must have same size");
    }
    
    let stripe_size = old_parity.len();
    let mut new_parity = vec![0u8; stripe_size];
    
    for i in 0..stripe_size {
        new_parity[i] = old_parity[i] ^ old_data[i] ^ new_data[i];
    }
    
    new_parity
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_xor_parity_basic() {
        let d1 = vec![1u8, 2, 3, 4];
        let d2 = vec![5u8, 6, 7, 8];
        let d3 = vec![9u8, 10, 11, 12];
        
        let parity = calculate_xor_parity(&[d1.clone(), d2.clone(), d3.clone()]);
        
        assert_eq!(parity, vec![1^5^9, 2^6^10, 3^7^11, 4^8^12]);
    }
    
    #[test]
    fn test_reconstruct_single_disk_failure() {
        let d1 = vec![1u8, 2, 3, 4];
        let d2 = vec![5u8, 6, 7, 8];
        let d3 = vec![9u8, 10, 11, 12];
        
        let parity = calculate_xor_parity(&[d1.clone(), d2.clone(), d3.clone()]);
        
        let reconstructed_d2 = reconstruct_missing_data(&[d1.clone(), d3.clone()], &parity, 1);
        
        assert_eq!(reconstructed_d2, d2);
    }
    
    #[test]
    fn test_update_parity() {
        let old_data = vec![1u8, 2, 3, 4];
        let new_data = vec![10u8, 20, 30, 40];
        let d2 = vec![5u8, 6, 7, 8];
        let d3 = vec![9u8, 10, 11, 12];
        
        let old_parity = calculate_xor_parity(&[old_data.clone(), d2.clone(), d3.clone()]);
        let new_parity = calculate_new_parity(&old_parity, &old_data, &new_data);
        
        let expected_parity = calculate_xor_parity(&[new_data.clone(), d2.clone(), d3.clone()]);
        assert_eq!(new_parity, expected_parity);
    }
}