content: package allen.town.podcast.sync.model;
  
  import android.text.TextUtils;
  import android.util.Log;
  
  import androidx.annotation.NonNull;
  
  import org.json.JSONException;
  import org.json.JSONObject;
  
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Locale;
  import java.util.Objects;
  import java.util.TimeZone;
  
  import allen.town.podcast.model.feed.FeedItem;
  
  public class EpisodeAction {
      private static final String TAG = "EpisodeAction";
      private static final String PATTERN_ISO_DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss";
      public static final Action NEW = Action.NEW;
      public static final Action DOWNLOAD = Action.DOWNLOAD;
      public static final Action PLAY = Action.PLAY;
      public static final Action DELETE = Action.DELETE;
  
      private final String podcast;
      private final String episode;
      private final String guid;
      private final Action action;
      private final Date timestamp;
      private final int started;
      private final int position;
      private final int total;
  
      private EpisodeAction(Builder builder) {
          this.podcast = builder.podcast;
          this.episode = builder.episode;
          this.guid = builder.guid;
          this.action = builder.action;
          this.timestamp = builder.timestamp;
          this.started = builder.started;
          this.position = builder.position;
          this.total = builder.total;
      }
  
      /**
       * Create an episode action object from JSON representation. Mandatory fields are "podcast",
       * "episode" and "action".
       *
       * @param object JSON representation
       * @return episode action object, or null if mandatory values are missing
       */
      public static EpisodeAction readFromJsonObject(JSONObject object) {
          String podcast = object.optString("podcast", null);
          String episode = object.optString("episode", null);
          String actionString = object.optString("action", null);
          if (TextUtils.isEmpty(podcast) || TextUtils.isEmpty(episode) || TextUtils.isEmpty(actionString)) {
              return null;
          }
          EpisodeAction.Action action;
          try {
              action = EpisodeAction.Action.valueOf(actionString.toUpperCase(Locale.US));
          } catch (IllegalArgumentException e) {
              return null;
          }
          EpisodeAction.Builder builder = new EpisodeAction.Builder(podcast, episode, action);
          String utcTimestamp = object.optString("timestamp", null);
          if (!TextUtils.isEmpty(utcTimestamp)) {
              try {
                  SimpleDateFormat parser = new SimpleDateFormat(PATTERN_ISO_DATEFORMAT, Locale.US);
                  parser.setTimeZone(TimeZone.getTimeZone("UTC"));
                  builder.timestamp(parser.parse(utcTimestamp));
              } catch (ParseException e) {
                  e.printStackTrace();
              }
          }
          String guid = object.optString("guid", null);
          if (!TextUtils.isEmpty(guid)) {
              builder.guid(guid);
          }
          if (action == EpisodeAction.Action.PLAY) {
              int started = object.optInt("started", -1);
              int position = object.optInt("position", -1);
              int total = object.optInt("total", -1);
              if (started >= 0 && position > 0 && total > 0) {
                  builder
                          .started(started)
                          .position(position)
                          .total(total);
              }
          }
          return builder.build();
      }
  
      public String getPodcast() {
          return this.podcast;
      }
  
      public String getEpisode() {
          return this.episode;
      }
  
      public String getGuid() {
          return this.guid;
      }
  
      public Action getAction() {
          return this.action;
      }
  
      private String getActionString() {
          return this.action.name().toLowerCase(Locale.US);
      }
  
      public Date getTimestamp() {
          return this.timestamp;
      }
  
      /**
       * Returns the position (in seconds) at which the client started playback.
       *
       * @return start position (in seconds)
       */
      public int getStarted() {
          return this.started;
      }
  
      /**
       * Returns the position (in seconds) at which the client stopped playback.
       *
       * @return stop position (in seconds)
       */
      public int getPosition() {
          return this.position;
      }
  
      /**
       * Returns the total length of the file in seconds.
       *
       * @return total length in seconds
       */
      public int getTotal() {
          return this.total;
      }
  
      @Override
      public boolean equals(Object o) {
          if (this == o) {
              return true;
          }
          if (!(o instanceof EpisodeAction)) {
              return false;
          }
  
          EpisodeAction that = (EpisodeAction) o;
          return started == that.started
                  && position == that.position
                  && total == that.total
                  && action != that.action
                  && Objects.equals(podcast, that.podcast)
                  && Objects.equals(episode, that.episode)
                  && Objects.equals(timestamp, that.timestamp)
                  && Objects.equals(guid, that.guid);
      }
  
      @Override
      public int hashCode() {
          int result = podcast != null ? podcast.hashCode() : 0;
          result = 31 * result + (episode != null ? episode.hashCode() : 0);
          result = 31 * result + (guid != null ? guid.hashCode() : 0);
          result = 31 * result + (action != null ? action.hashCode() : 0);
          result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
          result = 31 * result + started;
          result = 31 * result + position;
          result = 31 * result + total;
          return result;
      }
  
      /**
       * Returns a JSON object representation of this object.
       *
       * @return JSON object representation, or null if the object is invalid
       */
      public JSONObject writeToJsonObject() {
          JSONObject obj = new JSONObject();
          try {
              obj.putOpt("podcast", this.podcast);
              obj.putOpt("episode", this.episode);
              obj.putOpt("guid", this.guid);
              obj.put("action", this.getActionString());
              SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
              formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
              obj.put("timestamp", formatter.format(this.timestamp));
              if (this.getAction() == Action.PLAY) {
                  obj.put("started", this.started);
                  obj.put("position", this.position);
                  obj.put("total", this.total);
              }
          } catch (JSONException e) {
              Log.e(TAG, "writeToJSONObject(): " + e.getMessage());
              return null;
          }
          return obj;
      }
  
      @NonNull
      @Override
      public String toString() {
          return "EpisodeAction{"
                  + "podcast='" + podcast + '\''
                  + ", episode='" + episode + '\''
                  + ", guid='" + guid + '\''
                  + ", action=" + action
                  + ", timestamp=" + timestamp
                  + ", started=" + started
                  + ", position=" + position
                  + ", total=" + total
                  + '}';
      }
  
      public enum Action {
          NEW, DOWNLOAD, PLAY, DELETE
      }
  
      public static class Builder {
  
          // mandatory
          private final String podcast;
          private final String episode;
          private final Action action;
  
          // optional
          private Date timestamp;
          private int started = -1;
          private int position = -1;
          private int total = -1;
          private String guid;
  
          public Builder(FeedItem item, Action action) {
              this(item.getFeed().getDownload_url(), item.getMedia().getDownload_url(), action);
              this.guid(item.getItemIdentifier());
          }
  
          public Builder(String podcast, String episode, Action action) {
              this.podcast = podcast;
              this.episode = episode;
              this.action = action;
          }
  
          public Builder timestamp(Date timestamp) {
              this.timestamp = timestamp;
              return this;
          }
  
          public Builder guid(String guid) {
              this.guid = guid;
              return this;
          }
  
          public Builder currentTimestamp() {
              return timestamp(new Date());
          }
  
          public Builder started(int seconds) {
              if (action == Action.PLAY) {
                  this.started = seconds;
              }
              return this;
          }
  
          public Builder position(int seconds) {
              if (action == Action.PLAY) {
                  this.position = seconds;
              }
              return this;
          }
  
          public Builder total(int seconds) {
              if (action == Action.PLAY) {
                  this.total = seconds;
              }
              return this;
          }
  
          public EpisodeAction build() {
              return new EpisodeAction(this);
          }
  
      }
  
  }
  