use crate::frame::{Frame, Message, Opcode};

pub trait AsFrame {
    /// Gets a Frame for this type, ready to be sent over the network
    fn as_frame(&self, mask: bool) -> Frame;
}
pub trait FromFrame {
    /// Converts a Frame received over the network into this type, to be passed to the application
    fn from_frame(frame: &Frame) -> Self;
}

impl AsFrame for Message {
    fn as_frame(&self, mask: bool) -> Frame {
        let (payload, opcode) = match self {
            Message::Text(txt) => (txt.as_bytes().to_vec(), Opcode::Text),
            Message::Binary(bin) => (bin.clone(), Opcode::Binary),
            Message::Ping(bin) => (bin.clone(), Opcode::Ping),
            Message::Pong(bin) => (bin.clone(), Opcode::Pong)
        };
        Frame {
            fin: true,
            rsv1: false,
            rsv2: false,
            rsv3: false,
            opcode,
            mask,
            payload_len: payload.len() as u64,
            masking_key: if mask { Some(crate::random::masking_key()) } else { None },
            payload_data: payload,
        }
    }
}
impl FromFrame for Message {
    fn from_frame(frame: &Frame) -> Self {
        match frame.opcode {
            Opcode::Continuation => panic!("Message::from_frame called with a continuation frame"),
            Opcode::Text => Self::Text(String::from_utf8_lossy(&frame.payload_data).to_string()),
            Opcode::Binary => Self::Binary(frame.payload_data.clone()),
            Opcode::ConnectionClose => panic!("Message::from_frame called with a close frame"),
            Opcode::Ping => Self::Ping(frame.payload_data.clone()),
            Opcode::Pong => Self::Pong(frame.payload_data.clone())
        }
    }
}