content: /*
   * To change this license header, choose License Headers in Project Properties.
   * To change this template file, choose Tools | Templates
   * and open the template in the editor.
   */
  
  package tools.packets;
  
  import client.inventory.Item;
  import client.MapleCharacter;
  import java.util.ArrayList;
  import java.util.List;
  import tools.MaplePacketCreator;
  import tools.StringUtil;
  import tools.data.output.MaplePacketLittleEndianWriter;
  
  /**
   * CField_Wedding, CField_WeddingPhoto, CWeddingMan, OnMarriageResult, and all Wedding/Marriage enum/structs.
   * 
   * @author Eric
   * 
   * Wishlists edited by Drago (Dragohe4rt)
   */
  public class Wedding extends MaplePacketCreator {
      private static final short MARRIAGE_REQUEST = 0x48;
      private static final short MARRIAGE_RESULT = 0x49;
      private static final short WEDDING_GIFT_RESULT = 0x4A;
      private static final short NOTIFY_MARRIED_PARTNER_MAP_TRANSFER = 0x4B;
      private static final short WEDDING_PHOTO = 0x2B;
      private static final short WEDDING_PROGRESS = 0x140;
      private static final short WEDDING_CEREMONY_END = 0x141;
      
      /*
          00000000 CWeddingMan     struc ; (sizeof=0x104)
          00000000 vfptr           dd ?                    ; offset
          00000004 ___u1           $01CBC6800BD386B8A8FD818EAD990BEC ?
          0000000C m_mCharIDToMarriageNo ZMap<unsigned long,unsigned long,unsigned long> ?
          00000024 m_mReservationPending ZMap<unsigned long,ZRef<GW_WeddingReservation>,unsigned long> ?
          0000003C m_mReservationPendingGroom ZMap<unsigned long,ZRef<CUser>,unsigned long> ?
          00000054 m_mReservationPendingBride ZMap<unsigned long,ZRef<CUser>,unsigned long> ?
          0000006C m_mReservationStartUser ZMap<unsigned long,unsigned long,unsigned long> ?
          00000084 m_mReservationCompleted ZMap<unsigned long,ZRef<GW_WeddingReservation>,unsigned long> ?
          0000009C m_mGroomWishList ZMap<unsigned long,ZRef<ZArray<ZXString<char> > >,unsigned long> ?
          000000B4 m_mBrideWishList ZMap<unsigned long,ZRef<ZArray<ZXString<char> > >,unsigned long> ?
          000000CC m_mEngagementPending ZMap<unsigned long,ZRef<GW_MarriageRecord>,unsigned long> ?
          000000E4 m_nCurrentWeddingState dd ?
          000000E8 m_dwCurrentWeddingNo dd ?
          000000EC m_dwCurrentWeddingMap dd ?
          000000F0 m_bIsReservationLoaded dd ?
          000000F4 m_dwNumGuestBless dd ?
          000000F8 m_bPhotoSuccess dd ?
          000000FC m_tLastUpdate   dd ?
          00000100 m_bStartWeddingCeremony dd ?
          00000104 CWeddingMan     ends
      */
      
      public class Field_Wedding {
          public int m_nNoticeCount;
          public int m_nCurrentStep;
          public int m_nBlessStartTime;
      }
      
      public class Field_WeddingPhoto {
          public boolean m_bPictureTook;
      }
      
      public class GW_WeddingReservation {
          public int dwReservationNo;
          public int dwGroom, dwBride;
          public String sGroomName, sBrideName;
          public int usWeddingType;
      }
      
      public class WeddingWishList {
          public MapleCharacter pUser;
          public int dwMarriageNo;
          public int nGender;
          public int nWLType;
          public int nSlotCount;
          public List<String> asWishList = new ArrayList<>();
          public int usModifiedFlag; // dword
          public boolean bLoaded;
      }
      
      public class GW_WeddingWishList {
          public final int WEDDINGWL_MAX = 0xA; // enum WEDDINGWL
          public int dwReservationNo;
          public byte nGender;
          public String sItemName;
      }
      
      public enum MarriageStatus {
          SINGLE(0x0),
          ENGAGED(0x1),
          RESERVED(0x2),
          MARRIED(0x3);
          private int ms;
          private MarriageStatus(int ms) {
              this.ms = ms;
          }
          
          public int getMarriageStatus() {
              return ms;
          }
      }
      
      public enum MarriageRequest {
          AddMarriageRecord(0x0),
          SetMarriageRecord(0x1),
          DeleteMarriageRecord(0x2),
          LoadReservation(0x3),
          AddReservation(0x4),
          DeleteReservation(0x5),
          GetReservation(0x6);
          private int req;
          private MarriageRequest(int req) {
              this.req = req;
          }
          
          public int getMarriageRequest() {
              return req;
          }
      }
      
      public enum WeddingType {
          CATHEDRAL(0x1),
          VEGAS(0x2),
          CATHEDRAL_PREMIUM(0xA),
          CATHEDRAL_NORMAL(0xB),
          VEGAS_PREMIUM(0x14),
          VEGAS_NORMAL(0x15);
          private int wt;
          private WeddingType(int wt) {
              this.wt = wt;
          }
          
          public int getType() {
              return wt;
          }
      }
      
      public enum WeddingMap {
          WEDDINGTOWN(680000000),
          CHAPEL_STARTMAP(680000110),
          CATHEDRAL_STARTMAP(680000210),
          PHOTOMAP(680000300),
          EXITMAP(680000500);
          private int wm;
          private WeddingMap(int wm) {
              this.wm = wm;
          }
          
          public int getMap() {
              return wm;
          }
      }
      
      public enum WeddingItem {
          WR_MOONSTONE(1112803), // Wedding Ring
          WR_STARGEM(1112806),
          WR_GOLDENHEART(1112807),
          WR_SILVERSWAN(1112809),
          ERB_MOONSTONE(2240000), // Engagement Ring Box
          ERB_STARGEM(2240001),
          ERB_GOLDENHEART(2240002),
          ERB_SILVERSWAN(2240003),
          ERBE_MOONSTONE(4031357), // Engagement Ring Box (Empty)
          ER_MOONSTONE(4031358), // Engagement Ring
          ERBE_STARGEM(4031359),
          ER_STARGEM(4031360),
          ERBE_GOLDENHEART(4031361),
          ER_GOLDENHEART(4031362),
          ERBE_SILVERSWAN(4031363),
          ER_SILVERSWAN(4031364),
          PARENTS_BLESSING(4031373), // Parents Blessing
          OFFICIATORS_PERMISSION(4031374), // Officiator's Permission
          WR_CATHEDRAL_PREMIUM(4031375), // Wedding Ring?
          WR_VEGAS_PREMIUM(4031376),
          IB_VEGAS(4031377),      // toSend invitation
          IB_CATHEDRAL(4031395),  // toSend invitation
          IG_VEGAS(4031406),      // rcvd invitation
          IG_CATHEDRAL(4031407),  // rcvd invitation
          OB_FORCOUPLE(4031424), // Onyx Box? For Couple
          WR_CATHEDRAL_NORMAL(4031480), // Wedding Ring?
          WR_VEGAS_NORMAL(4031481),
          WT_CATHEDRAL_NORMAL(5251000), // Wedding Ticket
          WT_VEGAS_NORMAL(5251001),
          WT_VEGAS_PREMIUM(5251002),
          WT_CATHEDRAL_PREMIUM(5251003);
          private int wi;
          private WeddingItem(int wi) {
              this.wi = wi;
          }
          
          public int getItem() {
              return wi;
          }
      }
      
      /**
       * <name> has requested engagement. Will you accept this proposal?
       * 
       *    @param name
       *    @param playerid
       *    @return mplew
       */
      public static byte[] OnMarriageRequest(String name, int playerid) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(MARRIAGE_REQUEST);
          mplew.write(0); //mode, 0 = engage, 1 = cancel, 2 = answer.. etc
          mplew.writeMapleAsciiString(name); // name
          mplew.writeInt(playerid); // playerid
          return mplew.getPacket();
      }
      
      /**
       * A quick rundown of how (I think based off of enough BMS searching) WeddingPhoto_OnTakePhoto works:
       * - We send this packet with (first) the Groom / Bride IGNs
       * - We then send a fieldId (unsure about this part at the moment, 90% sure it's the id of the map)
       * - After this, we write an integer of the amount of characters within the current map (which is the Cake Map -- exclude users within Exit Map)
       * - Once we've retrieved the size of the characters, we begin to write information about them (Encode their name, guild, etc info)
       * - Now that we've Encoded our character data, we begin to Encode the ScreenShotPacket which requires a TemplateID, IGN, and their positioning
       * - Finally, after encoding all of our data, we send this packet out to a MapGen application server
       * - The MapGen server will then retrieve the packet byte array and convert the bytes into a ImageIO 2D JPG output
       * - The result after converting into a JPG will then be remotely uploaded to /weddings/ with ReservedGroomName_ReservedBrideName to be displayed on the web server.
       * 
       * - Will no longer continue Wedding Photos, needs a WvsMapGen :(
       * 
       *    @param ReservedGroomName The groom IGN of the wedding
       *    @param ReservedBrideName The bride IGN of the wedding
       *    @param m_dwField The current field id (the id of the cake map, ex. 680000300)
       *    @param m_uCount The current user count (equal to m_dwUsers.size)
       *    @param m_dwUsers The List of all MapleCharacter guests within the current cake map to be encoded
       *    @return mplew (MaplePacket) Byte array to be converted and read for byte[]->ImageIO
       */
      public static byte[] OnTakePhoto(String ReservedGroomName, String ReservedBrideName, int m_dwField, List<MapleCharacter> m_dwUsers) { // OnIFailedAtWeddingPhotos
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(WEDDING_PHOTO); // v53 header, convert -> v83
          mplew.writeMapleAsciiString(ReservedGroomName);
          mplew.writeMapleAsciiString(ReservedBrideName);
          mplew.writeInt(m_dwField); // field id?
          mplew.writeInt(m_dwUsers.size());
          
          for (MapleCharacter guest : m_dwUsers) {
              // Begin Avatar Encoding
              addCharLook(mplew, guest, false); // CUser::EncodeAvatar
              mplew.writeInt(30000); // v20 = *(_DWORD *)(v13 + 2192) -- new groom marriage ID??
              mplew.writeInt(30000); // v20 = *(_DWORD *)(v13 + 2192) -- new bride marriage ID??
              mplew.writeMapleAsciiString(guest.getName());
              mplew.writeMapleAsciiString(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getName() : "");
              mplew.writeShort(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogoBG() : 0);
              mplew.write(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogoBGColor() : 0);
              mplew.writeShort(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogo() : 0);
              mplew.write(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogoColor() : 0);
              mplew.writeShort(guest.getPosition().x); // v18 = *(_DWORD *)(v13 + 3204);
              mplew.writeShort(guest.getPosition().y); // v20 = *(_DWORD *)(v13 + 3208);
              // Begin Screenshot Encoding
              mplew.write(1); // // if ( *(_DWORD *)(v13 + 288) ) { COutPacket::Encode1(&thisa, v20);
              // CPet::EncodeScreenShotPacket(*(CPet **)(v13 + 288), &thisa);
              mplew.writeInt(1); // dwTemplateID
              mplew.writeMapleAsciiString(guest.getName()); // m_sName
              mplew.writeShort(guest.getPosition().x); // m_ptCurPos.x
              mplew.writeShort(guest.getPosition().y); // m_ptCurPos.y
              mplew.write(guest.getStance()); // guest.m_bMoveAction
          }
          
          return mplew.getPacket();
      }
      
      /**
       * Enable spouse chat and their engagement ring without @relog
       * 
       *    @param marriageId
       *    @param chr
       *    @param wedding
       *    @return mplew
       */
      public static byte[] OnMarriageResult(int marriageId, MapleCharacter chr, boolean wedding) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(MARRIAGE_RESULT);
          mplew.write(11);
          mplew.writeInt(marriageId);
          mplew.writeInt(chr.getGender() == 0 ? chr.getId() : chr.getPartnerId());
          mplew.writeInt(chr.getGender() == 0 ? chr.getPartnerId() : chr.getId());
          mplew.writeShort(wedding ? 3 : 1);
          if (wedding) {
              mplew.writeInt(chr.getMarriageItemId());
              mplew.writeInt(chr.getMarriageItemId());
          } else {
              mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement)
              mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement)
          }
          mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getName() : MapleCharacter.getNameById(chr.getPartnerId()), '\0', 13));
          mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? MapleCharacter.getNameById(chr.getPartnerId()) : chr.getName(), '\0', 13));
          
          return mplew.getPacket();
      }
      
      /**
       * To exit the Engagement Window (Waiting for her response...), we send a GMS-like pop-up.
       * 
       *    @param msg
       *    @return mplew
       */
      public static byte[] OnMarriageResult(final byte msg) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(MARRIAGE_RESULT);
          mplew.write(msg);
          if (msg == 36) {
              mplew.write(1);
              mplew.writeMapleAsciiString("You are now engaged.");
          }
          return mplew.getPacket();
      }
      
      /**
       * The World Map includes 'loverPos' in which this packet controls
       * 
       *    @param partner
       *    @param mapid
       *    @return mplew
       */
      public static byte[] OnNotifyWeddingPartnerTransfer(int partner, int mapid) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(NOTIFY_MARRIED_PARTNER_MAP_TRANSFER);
          mplew.writeInt(mapid);
          mplew.writeInt(partner);
          
          return mplew.getPacket();
      }
      
      /**
       * The wedding packet to display Pelvis Bebop and enable the Wedding Ceremony Effect between two characters
       * CField_Wedding::OnWeddingProgress - Stages
       * CField_Wedding::OnWeddingCeremonyEnd - Wedding Ceremony Effect
       * 
       *    @param SetBlessEffect
       *    @param groom
       *    @param bride
       *    @param step
       *    @return mplew
       */
      public static byte[] OnWeddingProgress(boolean SetBlessEffect, int groom, int bride, byte step) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(SetBlessEffect ? WEDDING_CEREMONY_END : WEDDING_PROGRESS);
          if (!SetBlessEffect) { // in order for ceremony packet to send, byte step = 2 must be sent first
              mplew.write(step);
          }
          mplew.writeInt(groom);
          mplew.writeInt(bride);
          return mplew.getPacket();
      }
      
      /**
       * When we open a Wedding Invitation, we display the Bride & Groom
       * 
       *    @param groom
       *    @param bride
       *    @return mplew
       */
      public static byte[] sendWeddingInvitation(String groom, String bride) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(MARRIAGE_RESULT);
          mplew.write(15);
          mplew.writeMapleAsciiString(groom);
          mplew.writeMapleAsciiString(bride);
          mplew.writeShort(1); // 0 = Cathedral Normal?, 1 = Cathedral Premium?, 2 = Chapel Normal?
          return mplew.getPacket();
      }
      
      public static byte[] sendWishList() { // fuck my life
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(MARRIAGE_REQUEST);
          mplew.write(9);
          return mplew.getPacket();
      }
  
      /**
       * Handles all of WeddingWishlist packets 
       * 
       *    @param mode
       *    @param itemnames
       *    @param items
       *    @return mplew
       */
      public static byte[] OnWeddingGiftResult(byte mode, List<String> itemnames, List<Item> items) {
          MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
          mplew.writeShort(WEDDING_GIFT_RESULT);
          mplew.write(mode);
          switch (mode) {
              case 0xC: // 12 : You cannot give more than one present for each wishlist 
              case 0xE: // 14 : Failed to send the gift.
                  break;
              
              case 0x09: { // Load Wedding Registry
                  mplew.write(itemnames.size());
                  for (String names : itemnames) {
                      mplew.writeMapleAsciiString(names);
                  }
                  break;
              }
              case 0xA: // Load Bride's Wishlist 
              case 0xF: // 10, 15, 16 = CWishListRecvDlg::OnPacket
              case 0xB: { // Add Item to Wedding Registry 
                  // 11 : You have sent a gift | | 13 : Failed to send the gift. | 
                  if (mode == 0xB) {
                      mplew.write(itemnames.size());
                      for (String names : itemnames) {
                          mplew.writeMapleAsciiString(names);
                      }
                  }
                  mplew.writeLong(32);
                  mplew.write(items.size());
                  for (Item item : items) {
                      addItemInfo(mplew, item, true);
                  }
                  break;
              }
              default: {
                  System.out.println("Unknown Wishlist Mode: " + mode);
                  break;
              }
          }
          return mplew.getPacket();
      }
  } 