public class PlayerActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private static final String TAG = "PlayerActivity";

    private IjkVideoView videoView;
    private TextView toastTextView;
    private AndroidMediaController mediaController;
    private ProgressBar progressBar;

    private Settings settings;
    private WifiManager.WifiLock wifiLock;

    Movie movie;
    String trailerID;
    String trailerURL;
    TorrentFile torrentFile;

    private int retry = 1;
    private int savedPosition = 0;

    String subtitleDir;
    ArrayList<Subtitle> subtitles;
    int subtitleDelay = 0;
    int subtitleCurrent = 0;

    Collection<Caption> captions;
    public TimedTextObject timedTextObject;
    private TextView subtitleTextView;
    private SubtitleTask subtitleTask;

    private Handler subtitleHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_player);

        settings = new Settings(this);

        Bundle bundle = getIntent().getExtras();
        movie = (Movie) bundle.get("movie");
        subtitles = (ArrayList<Subtitle>) bundle.get("subtitles");
        torrentFile = (TorrentFile) bundle.get("torrent-file");
        trailerID = (String) bundle.get("trailer-id");
        trailerURL = (String) bundle.get("trailer-url");

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        setTitle();

        ActionBar actionBar = getSupportActionBar();

        mediaController = new AndroidMediaController(this, false);
        mediaController.setSupportActionBar(actionBar);

        subtitleTextView = (TextView) findViewById(R.id.subtitle_view);
        toastTextView = (TextView) findViewById(R.id.toast_text_view);

        progressBar = (ProgressBar) findViewById(R.id.progress_bar);
        progressBar.setVisibility(View.VISIBLE);

        subtitleDir = Storage.getStorage(this) + File.separator + "bukanir" + File.separator + "subtitles";

        initVideoView();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause");
        super.onPause();
        if(subtitleHandler != null) {
            subtitleHandler.removeCallbacks(subtitleProcessesor);

            if(subtitleTask != null) {
                subtitleTask.cancel(true);
            }
        }

        if(videoView != null) {
            savedPosition = videoView.getCurrentPosition();
            if(videoView.isPlaying()) {
                videoView.stopPlayback();
            }
            videoView.release(true);
        }

        IjkMediaPlayer.native_profileEnd();
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onPause");
        super.onResume();
        if(videoView != null && savedPosition > 0) {
            if(settings.seek()) {
                videoView.seekTo(savedPosition);
            }
            savedPosition = 0;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        int wifiLockMode;
        if(settings.wifiHigh()) {
            wifiLockMode = WifiManager.WIFI_MODE_FULL_HIGH_PERF;
        } else {
            wifiLockMode = WifiManager.WIFI_MODE_FULL;
        }
        wifiLock = ((WifiManager) this.getSystemService(Context.WIFI_SERVICE))
                .createWifiLock(wifiLockMode, "lock");
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        if(wifiLock != null) {
            if(wifiLock.isHeld()) {
                wifiLock.release();
                wifiLock = null;
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.player, menu);

        if(subtitles == null || subtitles.isEmpty()) {
            menu.findItem(R.id.action_toggle_subtitles).setVisible(false);
            menu.findItem(R.id.action_sub_delay_plus).setVisible(false);
            menu.findItem(R.id.action_sub_delay_minus).setVisible(false);
        } else {
            MenuItem item = menu.findItem(R.id.action_toggle_subtitles);
            if(subtitleCurrent == -1) {
                item.setIcon(R.drawable.ic_subtitles_off);
            } else {
                item.setIcon(R.drawable.ic_subtitles);
            }
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if(id == R.id.action_toggle_ratio) {
            int aspectRatio = videoView.toggleAspectRatio();
            String aspectRatioText = MeasureHelper.getAspectRatioText(this, aspectRatio);
            toastTextView.setText(aspectRatioText);
            mediaController.showOnce(toastTextView);
            return true;
        } else if(id == R.id.action_toggle_subtitles) {
            if(subtitles != null && !subtitles.isEmpty()) {
                toggleSubtitles();
            }
        } else if(id == R.id.action_sub_delay_plus) {
            subtitleDelay += 1;
            toastTextView.setText(String.format(Locale.ROOT, "Sub delay: %ds", subtitleDelay));
            mediaController.showOnce(toastTextView);
        } else if(id == R.id.action_sub_delay_minus) {
            subtitleDelay -= 1;
            toastTextView.setText(String.format(Locale.ROOT, "Sub delay: %ds", subtitleDelay));
            mediaController.showOnce(toastTextView);
        }

        return super.onOptionsItemSelected(item);
    }

    private void setTitle() {
        String dataTitle = "";
        if(torrentFile != null) {
            if(movie.category.equals("205") || movie.category.equals("208")) {
                int season = Integer.valueOf(movie.season);
                int episode = Integer.valueOf(movie.episode);
                dataTitle = String.format(Locale.ROOT, "%s (S%02dE%02d)", movie.title, season, episode);
            } else {
                dataTitle = String.format("%s (%s)", movie.title, movie.year);
            }
        } else if(trailerURL != null && !trailerURL.isEmpty() && !trailerURL.equals("null")) {
            dataTitle = String.format("%s (%s) - Trailer", movie.title, movie.year);
        }

        if(getSupportActionBar() != null) {
            getSupportActionBar().setTitle(dataTitle);
        }
    }

    private void setSeekVisibility() {
        if(!settings.seek() && trailerURL == null) {
            int progressId = getResources().getIdentifier("mediacontroller_progress", "id", "android");
            SeekBar seekBar = (SeekBar) mediaController.findViewById(progressId);
            if(seekBar != null) {
                seekBar.setVisibility(View.INVISIBLE);
            }
        }
    }

    private void initVideoView() {
        IjkMediaPlayer.loadLibrariesOnce(null);
        IjkMediaPlayer.native_profileBegin("libijkplayer.so");

        videoView = (IjkVideoView) findViewById(R.id.video_view);
        videoView.setMediaController(mediaController);

        subtitleTextView.setTextSize(Integer.valueOf(settings.subtitleSize()));

        videoView.getSurfaceRenderView().getHolder().addCallback(this);

        IMediaPlayer.OnPreparedListener preparedListener = new IMediaPlayer.OnPreparedListener() {
            public void onPrepared(IMediaPlayer mp) {
                if(progressBar != null) {
                    progressBar.setVisibility(View.GONE);
                }

                setSeekVisibility();

                if(subtitles != null && !subtitles.isEmpty()) {
                    subtitleTask = new SubtitleTask();
                    subtitleTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0);
                }

                wifiLock.acquire();
            }
        };

        IMediaPlayer.OnCompletionListener completionListener = new IMediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(IMediaPlayer mp) {
                onBackPressed();
            }
        };

        IMediaPlayer.OnInfoListener infoListener = new IMediaPlayer.OnInfoListener() {
            @Override
            public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
                if(arg1 == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
                    if(progressBar != null) {
                        progressBar.setVisibility(View.VISIBLE);
                    }
                } else if(arg1 == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
                    if(progressBar != null) {
                        progressBar.setVisibility(View.GONE);
                    }
                }
                return true;
            }
        };

        IMediaPlayer.OnErrorListener errorListener = new IMediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
                Log.d(TAG, "onError");

                if(trailerURL != null) {
                    if(retry >= 3) {
                        onBackPressed();
                        Toast.makeText(getApplicationContext(), R.string.error_text_connection, Toast.LENGTH_LONG).show();
                    } else {
                        Log.d(TAG, "retry " + String.valueOf(retry));
                        new TrailerTask().execute(trailerID);
                    }
                } else {
                    onBackPressed();
                    Toast.makeText(getApplicationContext(), R.string.error_text_connection, Toast.LENGTH_LONG).show();
                }
                return true;
            }
        };

        videoView.setOnPreparedListener(preparedListener);
        videoView.setOnCompletionListener(completionListener);
        videoView.setOnInfoListener(infoListener);
        videoView.setOnErrorListener(errorListener);

        String dataURI = "";
        if(torrentFile != null) {
            dataURI = torrentFile.url;
        } else if(trailerURL != null && !trailerURL.isEmpty() && !trailerURL.equals("null")) {
            dataURI = trailerURL;
        }

        if(dataURI != null) {
            videoView.setVideoURI(Uri.parse(dataURI));
        } else {
            Log.e(TAG, "Null dataURI");
            finish();
            return;
        }
        videoView.start();
    }

    private void toggleSubtitles() {
        int count;
        if(subtitles.size() > 3) {
            count = 2;
        } else {
            count = subtitles.size()-1;
        }

        subtitleCurrent++;
        if(subtitleCurrent > count) {
            subtitleCurrent = -1;
        }

        if(subtitleHandler != null) {
            subtitleHandler.removeCallbacks(subtitleProcessesor);
            if(subtitleTask != null) {
                subtitleTask.cancel(true);
            }

            invalidateOptionsMenu();
            if(subtitleCurrent != -1) {
                subtitleTask = new SubtitleTask();
                subtitleTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, subtitleCurrent);
            } else {
                subtitleTextView.setVisibility(View.INVISIBLE);
                toastTextView.setText(getString(R.string.sub_disabled));
                mediaController.showOnce(toastTextView);
            }
        }
    }

    private Runnable subtitleProcessesor = new Runnable() {
        @Override
        public void run() {
            if(videoView != null && videoView.isPlaying()) {
                int currentPos = videoView.getCurrentPosition();
                for(Caption caption : captions) {
                    if(currentPos >= caption.start.getMseconds()+subtitleDelay*1000 &&
                            currentPos <= caption.end.getMseconds()+subtitleDelay*1000) {
                        onTimedText(caption);
                        break;
                    } else if(currentPos > caption.end.getMseconds()+subtitleDelay*1000) {
                        onTimedText(null);
                    }
                }
            }
            subtitleHandler.postDelayed(this, 500);
        }
    };

    public void onTimedText(Caption text) {
        if(text == null) {
            subtitleTextView.setVisibility(View.INVISIBLE);
            return;
        }
        subtitleTextView.setText(Html.fromHtml(text.content));
        subtitleTextView.setVisibility(View.VISIBLE);
    }

    public class SubtitleTask extends AsyncTask<Integer, Void, Subtitle> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Subtitle doInBackground(Integer... params) {
            try {
                Subtitle subtitle = subtitles.get(params[0]);
                String subtitleFile = BukanirClient.unzipSubtitle(subtitle.downloadLink, subtitleDir);

                if(subtitleFile.toLowerCase().endsWith(".srt")) {
                    timedTextObject = new FormatSRT().parseFile(subtitleFile);
                } else if(subtitleFile.toLowerCase().endsWith(".ass") || subtitleFile.toLowerCase().endsWith(".ssa")) {
                    timedTextObject = new FormatASS().parseFile(subtitleFile);
                }

                if(timedTextObject != null) {
                    captions = timedTextObject.captions.values();
                }

                return subtitle;
            } catch(Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        protected void onPostExecute(Subtitle s) {
            if(timedTextObject != null) {
                subtitleTextView.setText("");
                if(subtitleHandler != null) {
                    subtitleHandler.post(subtitleProcessesor);
                }
            }
            toastTextView.setText(String.format(Locale.ROOT, "Subtitle %d", subtitleCurrent+1));
            mediaController.showOnce(toastTextView);
            super.onPostExecute(s);
        }
    }

    private class TrailerTask extends AsyncTask<String, Void, String> {

        protected String doInBackground(String... params) {
            String video = params[0];
            String result = BukanirClient.getTrailer(video);

            if(isCancelled()) {
                return null;
            }

            return result;
        }

        protected void onPostExecute(String url) {
            retry += 1;
            if(url != null && !url.isEmpty() && !url.equals("empty")) {
                if(videoView != null) {
                    videoView.setVideoURI(Uri.parse(url));
                    videoView.start();
                }
            }
        }

    }

} public class Settings {

    private SharedPreferences preferences;

    public Settings(Context context) {
        Context context1 = context.getApplicationContext();
        preferences = PreferenceManager.getDefaultSharedPreferences(context1);
    }

    public int listCount() {
        return Integer.valueOf(preferences.getString("list_count", "30"));
    }

    public int cacheDays() {
        return Integer.valueOf(preferences.getString("cache_days", "7"));
    }

    public boolean eulaAccepted() {
        return preferences.getBoolean("eula_accepted", false);
    }

    public boolean hwDecode() {
        return preferences.getBoolean("hw_decode", false);
    }

    public boolean openSLES() {
        return preferences.getBoolean("open_sles", false);
    }

    public boolean seek() {
        return preferences.getBoolean("seek", true);
    }

    public String pixelFormat() {
        return preferences.getString("pixel_format", "");
    }

    public boolean wifiHigh() {
        return preferences.getBoolean("wifi_high", false);
    }

    public boolean subtitles() {
        return preferences.getBoolean("subtitles", true);
    }

    public String subtitleLanguage() {
        return preferences.getString("sub_lang", "English");
    }

    public String subtitleSize() {
        return preferences.getString("sub_size", "14");
    }

    public boolean keepFiles() {
        return preferences.getBoolean("keep_files", false);
    }

    public boolean encryption() {
        return preferences.getBoolean("encryption", true);
    }

    public String downloadRate() {
        return preferences.getString("download_rate", "-1");
    }

    public String uploadRate() {
        return preferences.getString("upload_rate", "-1");
    }

    public String listenPort() {
        return String.valueOf(preferences.getInt("listen_port", 6881));
    }

    public String tpbHost() {
        return String.valueOf(preferences.getString("tpb_host", "thepiratebay.org"));
    }

    public String eztvHost() {
        return String.valueOf(preferences.getString("eztv_host", "eztv.ag"));
    }

} public class BukanirClient {

    static {
        if(BuildConfig.DEBUG) {
            Bukanir.setVerbose(true);
        }
    }

    public static ArrayList<Movie> getTopResults(int category, int limit, int refresh, String cacheDir, int cacheDays, String tpbHost) {
        String result = null;
        try {
            result = Bukanir.category(category, limit, refresh, cacheDir, cacheDays, tpbHost);
        } catch(Exception e) {
            e.printStackTrace();
        }

        if(result == null || result.equals("empty")) {
            return null;
        }

        try {
            Type listType = new TypeToken<ArrayList<Movie>>() {}.getType();
            return new Gson().fromJson(result, listType);
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static ArrayList<Movie> getSearchResults(String query, int limit, int refresh, String cacheDir, int cacheDays, int pages, String tpbHost, String eztvHost) {
        String result = null;
        try {
            result = Bukanir.search(query, limit, refresh, cacheDir, cacheDays, pages, tpbHost, eztvHost);
        } catch(Exception e) {
            e.printStackTrace();
        }

        if(result == null || result.equals("empty")) {
            return null;
        }

        try {
            Type listType = new TypeToken<ArrayList<Movie>>() {}.getType();
            return new Gson().fromJson(result, listType);
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Summary getSummary(int id, int category, int season, int episode) {
        String result = null;
        try {
            result = Bukanir.summary(id, category, season, episode);
        } catch(Exception e) {
            e.printStackTrace();
        }

        if(result == null || result.equals("empty")) {
            return null;
        }

        try {
            return new Gson().fromJson(result, Summary.class);
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static ArrayList<Subtitle> getSubtitles(String movie, String year, String release, String language,
        String category, String season, String episode, String imdbId) {
        String result = null;
        try {
            result = Bukanir.subtitle(movie, year, release, language, Integer.valueOf(category), Integer.valueOf(season), Integer.valueOf(episode), imdbId);
        } catch(Exception e) {
            e.printStackTrace();
        }

        if(result == null || result.equals("empty")) {
            return null;
        }

        try {
            Type listType = new TypeToken<ArrayList<Subtitle>>() {}.getType();
            return new Gson().fromJson(result, listType);
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static ArrayList<AutoComplete> getAutoComplete(String query, int limit) {
        String result = null;
        try {
            result = Bukanir.autoComplete(query, limit);
        } catch(Exception e) {
            e.printStackTrace();
        }

        if(result == null || result.equals("empty")) {
            return null;
        }

        try {
            Type listType = new TypeToken<ArrayList<AutoComplete>>() {}.getType();
            return new Gson().fromJson(result, listType);
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getTrailer(String videoId) {
        String result = null;
        try {
            result = Bukanir.trailer(videoId);
        } catch(Exception e) {
            e.printStackTrace();
        }

        if(result == null || result.equals("empty")) {
            return null;
        }

        return result;
    }

    public static String unzipSubtitle(String url, String dest) {
        String result = null;
        try {
            result = Bukanir.unzipSubtitle(url, dest);
        } catch(Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    public static void cancel() {
        Bukanir.cancel();
    }

} public class Summary implements Serializable {

    public String id;
    public String video;
    public String director;
    public String rating;
    public String tagline;
    public String overview;
    public String runtime;
    public String imdbId;

    public List<String> cast;
    public List<String> genre;

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        String NL = System.getProperty("line.separator");

        result.append(((Object)this).getClass().getName() + " {" + NL);
        result.append("  id: " + this.id + NL);
        result.append("  video: " + this.video + NL);
        result.append("  director: " + this.director + NL);
        result.append("  rating: " + this.rating + NL);
        result.append("  tagline: " + this.tagline + NL);
        result.append("  overview: " + this.overview + NL);
        result.append("  runtime: " + this.runtime + NL);
        result.append("  imdbId: " + this.imdbId + NL);
        if(this.cast != null && !this.cast.isEmpty()) {
            result.append("  cast: " + android.text.TextUtils.join(", ", this.cast) + NL);
        }
        if(this.genre != null && !this.genre.isEmpty()) {
            result.append("  genre: " + android.text.TextUtils.join(", ", this.genre) + NL);
        }
        result.append("}" + NL);

        return result.toString();
    }

} public class Storage {

    public static final String TAG = "Storage";

    public static boolean isFreeSpaceAvailable(String storage, Long size) {
        long freeSpace = new File(storage).getUsableSpace();
        if(freeSpace > size) {
            return true;
        }
        return false;
    }

    private static File getDirectory(String variableName) {
        String path = System.getenv(variableName);
        if (!TextUtils.isEmpty(path)) {
            if (path.contains(":")) {
                for (String _path : path.split(":")) {
                    File file = new File(_path);
                    if (file.exists()) {
                        return file;
                    }
                }
            } else {
                File file = new File(path);
                if (file.exists()) {
                    return file;
                }
            }
        }
        return null;
    }

    public static String getStorage(Context context) {
        File externalStorage = null;
        File removableStorage = getDirectory("SECONDARY_STORAGE");

        String state = Environment.getExternalStorageState();
        if(Environment.MEDIA_MOUNTED.equals(state)) {
            externalStorage = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        }

        if(externalStorage != null && isFreeSpaceAvailable(externalStorage.toString(), (long) 1048576000) && externalStorage.canWrite()) {
            return externalStorage.toString();
        }

        if(removableStorage != null && isFreeSpaceAvailable(removableStorage.toString(), (long) 1048576000) && removableStorage.canWrite()) {
            return removableStorage.toString();
        }

        File hardcodeStorage = new File("/mnt/sdcard");
        if(isFreeSpaceAvailable(hardcodeStorage.toString(), (long) 1048576000) && hardcodeStorage.canWrite()) {
            return hardcodeStorage.toString();
        }

        return context.getCacheDir().toString();
    }

} public class Torrent2HttpClient {

    public boolean waitStartup() {
        return Bukanir.torrentWaitStartup();
    }

    public TorrentStatus getStatus() {
        String s = "";
        try {
            s = Bukanir.torrentStatus();
        } catch(Exception e) {
            e.printStackTrace();
        }

        try {
            Gson gson = new Gson();
            return gson.fromJson(s, TorrentStatus.class);
        } catch(Exception e) {
            return null;
        }
    }

    private TorrentFiles getFiles() {
        String s = "";
        try {
            s = Bukanir.torrentFiles();
        } catch(Exception e) {
            e.printStackTrace();
        }
        try {
            Gson gson = new Gson();
            return gson.fromJson(s, TorrentFiles.class);
        } catch(Exception e) {
            return null;
        }
    }

    public TorrentFile getLargestFile() {
        TorrentFiles torrentFiles = getFiles();
        if(torrentFiles != null && torrentFiles.files.size() > 0) {
            Collections.sort(torrentFiles.files);
            return torrentFiles.files.get(0);
        }
        return null;
    }

} public class Movie implements Comparable<Movie>, Serializable {

    public String id;
    public String title;
    public String year;
    public String posterSmall;
    public String posterMedium;
    public String posterLarge;
    public String posterXLarge;
    public String size;
    public String sizeHuman;
    public String seeders;
    public String magnetLink;
    public String release;
    public String category;
    public String season;
    public String episode;
    public String quality;

    @Override
    public int compareTo(@NonNull Movie m) {
        return Integer.valueOf(m.seeders) - Integer.valueOf(this.seeders);
    }

    @Override
    public boolean equals(Object obj) {
        if(obj == null) return false;
        if(obj == this) return true;
        if(!(obj instanceof Movie)) return false;
        Movie movie = (Movie) obj;
        return movie.id.equals(this.id);
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        String NL = System.getProperty("line.separator");

        result.append(((Object)this).getClass().getName() + " {" + NL);
        result.append("  title: " + this.title + NL);
        result.append("  id: " + this.id + NL);
        result.append("  year: " + this.year + NL);
        result.append("  posterSmall: " + this.posterSmall + NL);
        result.append("  posterMedium: " + this.posterMedium + NL);
        result.append("  posterLarge: " + this.posterLarge + NL);
        result.append("  posterXLarge: " + this.posterXLarge + NL);
        result.append("  size: " + this.size + NL);
        result.append("  sizeHuman: " + this.sizeHuman + NL);
        result.append("  seeders: " + this.seeders + NL);
        result.append("  magnetLink: " + this.magnetLink + NL);
        result.append("  release: " + this.release + NL);
        result.append("  category: " + this.category + NL);
        result.append("  season: " + this.season + NL);
        result.append("  episode: " + this.episode + NL);
        result.append("  quality: " + this.quality + NL);
        result.append("}" + NL);

        return result.toString();
    }

} public class Subtitle implements Comparable<Subtitle>, Serializable {

    public String id;
    public String title;
    public String year;
    public String release;
    public String downloadLink;
    public String score;

    @Override
    public int compareTo(Subtitle s) {
        if(s.score.isEmpty() || this.score.isEmpty()) {
            return 0;
        }
        return Double.compare(
                Double.parseDouble(s.score.replace(",", ".")),
                Double.parseDouble(this.score.replace(",", "."))
        );
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        String NL = System.getProperty("line.separator");

        result.append(((Object)this).getClass().getName() + " {" + NL);
        result.append("  id: " + this.id + NL);
        result.append("  title: " + this.title + NL);
        result.append("  year: " + this.year + NL);
        result.append("  release: " + this.release + NL);
        result.append("  downloadLink: " + this.downloadLink + NL);
        result.append("  score: " + this.score + NL);
        result.append("}" + NL);

        return result.toString();
    }

} public class TorrentFile implements Comparable<TorrentFile>, Serializable {

    public String name;
    public String save_path;
    public String url;
    public String size;
    public String offset;
    public String download;
    public String progress;

    @Override
    public int compareTo(TorrentFile f) {
        return (int) (Long.valueOf(f.size) - Long.valueOf(this.size));
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        String NL = System.getProperty("line.separator");

        result.append(((Object)this).getClass().getName() + " {" + NL);
        result.append("  name: " + this.name + NL);
        result.append("  save_path: " + this.save_path + NL);
        result.append("  url: " + this.url + NL);
        result.append("  size: " + this.size + NL);
        result.append("  offset: " + this.offset + NL);
        result.append("  download: " + this.download + NL);
        result.append("  progress: " + this.progress + NL);
        result.append("}" + NL);

        return result.toString();
    }

} public class TorrentStatus {

    public String name;
    public String state;
    public String state_str;
    public String error;
    public String progress;
    public String download_rate;
    public String upload_rate;
    public String total_download;
    public String total_upload;
    public String num_peers;
    public String num_seeds;
    public String total_seeds;
    public String total_peers;

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        String NL = System.getProperty("line.separator");

        result.append(((Object)this).getClass().getName() + " {" + NL);
        result.append("  name: " + this.name + NL);
        result.append("  state: " + this.state + NL);
        result.append("  state_str: " + this.state_str + NL);
        result.append("  error: " + this.error + NL);
        result.append("  progress: " + this.progress + NL);
        result.append("  download_rate: " + this.download_rate + NL);
        result.append("  upload_rate: " + this.upload_rate + NL);
        result.append("  total_download: " + this.total_download + NL);
        result.append("  total_upload: " + this.total_upload + NL);
        result.append("  num_peers: " + this.num_peers + NL);
        result.append("  num_seeds: " + this.num_seeds + NL);
        result.append("  total_seeds: " + this.total_seeds + NL);
        result.append("  total_peers: " + this.total_peers + NL);
        result.append("}" + NL);

        return result.toString();
    }
} public class Torrent2HttpService extends Service {

    public static final String TAG = "Torrent2HttpService";

    int id = 313;

    String magnetLink;

    File movieDir;
    File subtitlesDir;

    private Settings settings;
    private TorrentConfig config;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        settings = new Settings(this);
        config = new TorrentConfig();

        String storageDir = Storage.getStorage(this) + File.separator + "bukanir";
        movieDir = new File(storageDir + File.separator + "movies");
        subtitlesDir = new File(storageDir + File.separator + "subtitles");

        movieDir.mkdirs();
        subtitlesDir.mkdirs();
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();

        (new Thread() { public void run() {
            Bukanir.torrentStop();

            if(!settings.keepFiles()) {
                Log.d(TAG, "Removing files");
                if(movieDir != null && movieDir.exists()) {
                    Utils.deleteDir(movieDir);
                }
                if(subtitlesDir != null && subtitlesDir.exists()) {
                    Utils.deleteDir(subtitlesDir);
                }
            }
        }}).start();

        Toast.makeText(getApplicationContext(), getString(R.string.torrent_stopped), Toast.LENGTH_SHORT).show();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");

        magnetLink = intent.getExtras().getString("magnet");

        new Torrent2HttpThread().start();

        startNotification();
        Toast.makeText(this, getString(R.string.torrent_started), Toast.LENGTH_SHORT).show();

        return START_NOT_STICKY;
    }

    public void startNotification() {
        Intent i = new Intent(this, MovieActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendIntent = PendingIntent.getActivity(this, 0, i, 0);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setTicker(getString(R.string.torrent_started)).setContentTitle(getString(R.string.app_name))
                .setWhen(System.currentTimeMillis()).setAutoCancel(false)
                .setOngoing(true)
                .setContentIntent(pendIntent);
        Notification notification = builder.build();

        notification.flags |= Notification.FLAG_NO_CLEAR;
        startForeground(id, notification);
    }

    private class Torrent2HttpThread extends Thread {

        @Override
        public void run() {
            super.run();
            try {
                config.uri = magnetLink;
                config.download_path = movieDir.toString();
                config.listen_port = Integer.valueOf(settings.listenPort());
                config.max_download_rate = Integer.valueOf(settings.downloadRate());
                config.max_upload_rate = Integer.valueOf(settings.uploadRate());
                config.encryption = settings.encryption() ? 1 : 2;
                config.keep_files = true;

                config.no_sparse_file = !settings.seek();

                if(BuildConfig.DEBUG) {
                    config.verbose = true;
                }

                Gson gson = new Gson();
                Bukanir.torrentStartup(gson.toJson(config));
            } catch(Exception e){
                e.getMessage();
            }
        }

    }

} public class Utils {

    public static boolean isTorrentServiceRunning(Context context) {
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if(Torrent2HttpService.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    public static String toTitleCase(String input) {
        StringBuilder titleCase = new StringBuilder();
        boolean nextTitleCase = true;
        for(char c : input.toCharArray()) {
            if(Character.isSpaceChar(c)) {
                nextTitleCase = true;
            } else if(nextTitleCase) {
                c = Character.toTitleCase(c);
                nextTitleCase = false;
            }
            titleCase.append(c);
        }
        return titleCase.toString();
    }

    public static boolean deleteDir(File dir) {
        if (dir != null && dir.isDirectory()) {
            String[] children = dir.list();
            for (String aChildren : children) {
                boolean success = deleteDir(new File(dir, aChildren));
                if (!success) {
                    return false;
                }
            }
        }

        return dir != null && dir.delete();
    }

    public static Tracker getTracker(Context ctx) {
        Tracker tracker;
        String trackingId = "UA-60883832-1";
        Activity activity = (Activity) ctx;

        GoogleAnalytics analytics = GoogleAnalytics.getInstance(ctx);
        analytics.enableAutoActivityReports(activity.getApplication());
        analytics.setLocalDispatchPeriod(600);
        tracker = analytics.newTracker(trackingId);
        tracker.setAnonymizeIp(true);
        return tracker;
    }

    static long getUnixTime() {
        return System.currentTimeMillis() / 1000L;
    }

}
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.bukanir.android.activities.PlayerActivity;
import com.bukanir.android.application.Settings;
import com.bukanir.android.clients.BukanirClient;
import com.bukanir.android.R;
import com.bukanir.android.entities.Summary;
import com.bukanir.android.helpers.Storage;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.bukanir.android.clients.Torrent2HttpClient;
import com.bukanir.android.entities.Movie;
import com.bukanir.android.entities.Subtitle;
import com.bukanir.android.entities.TorrentFile;
import com.bukanir.android.entities.TorrentStatus;
import com.bukanir.android.services.Torrent2HttpService;
import com.bukanir.android.helpers.Utils;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Locale;

    public void startTrailerTask() {
        trailerTask = new TrailerTask();
        trailerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public void cancelTorrent2HttpTask() {
        if(torrent2HttpTask != null) {
            if(torrent2HttpTask.getStatus().equals(AsyncTask.Status.RUNNING)) {
                torrent2HttpTask.cancel(true);
                torrentProgressBar.setVisibility(View.INVISIBLE);
                downloadingText.setVisibility(View.INVISIBLE);
            }
        }
    }

    public void cancelTrailerTask() {
        if(trailerTask != null) {
            if(trailerTask.getStatus().equals(AsyncTask.Status.RUNNING)) {
                trailerTask.cancel(true);
                BukanirClient.cancel();
            }
        }
    }

    public void setMovieText(View rootView) {
        TextView title = (TextView) rootView.findViewById(R.id.title);
        TextView info = (TextView) rootView.findViewById(R.id.info);
        TextView genre = (TextView) rootView.findViewById(R.id.genre);
        TextView info2 = (TextView) rootView.findViewById(R.id.info2);
        TextView cast = (TextView) rootView.findViewById(R.id.cast);
        TextView director = (TextView) rootView.findViewById(R.id.director);
        TextView tagline = (TextView) rootView.findViewById(R.id.tagline);
        TextView overview = (TextView) rootView.findViewById(R.id.overview);

        if(movie == null || summary == null) {
            return;
        }

        title.setText(Utils.toTitleCase(movie.title));
        overview.setText(summary.overview);

        if(summary.cast != null) {
            String castText;
            if(summary.cast.size() >= 4) {
                castText = android.text.TextUtils.join(", ", summary.cast.subList(0, 4));
                if(summary.cast.size() > 4) {
                    castText += "...";
                }
            } else {
                castText = android.text.TextUtils.join(", ", summary.cast);
            }
            Spanned text = Html.fromHtml("<i>"+getString(R.string.cast_description)+"</i>" + castText);
            cast.setText(text);
        } else {
            cast.setVisibility(View.GONE);
        }

        if(summary.genre != null && !summary.genre.isEmpty()) {
            String genreText;
            if(summary.genre.size() > 3) {
                genreText = android.text.TextUtils.join(", ", summary.genre.subList(0, 3));
            } else {
                genreText = android.text.TextUtils.join(", ", summary.genre);
            }
            genre.setText(genreText);
        } else {
            genre.setVisibility(View.GONE);
        }

        if(!summary.director.isEmpty()) {
            Spanned text = Html.fromHtml("<i>"+getString(R.string.director_description)+"</i>" + summary.director);
            director.setText(text);
        } else {
            director.setVisibility(View.GONE);
        }

        if(movie.category.equals("205") || movie.category.equals("208")) {
            int season = Integer.valueOf(movie.season);
            int episode = Integer.valueOf(movie.episode);
            if(season != 0 && episode != 0) {
                tagline.setText(String.format(Locale.ROOT, "S%02dE%02d", season, episode));
            } else {
                tagline.setVisibility(View.GONE);
            }
        } else {
            if (!summary.tagline.isEmpty()) {
                tagline.setText(summary.tagline);
            } else {
                tagline.setVisibility(View.GONE);
            }
        }

        String year = "";
        if(!movie.year.isEmpty()) {
            year = String.format("(%s)  ", movie.year);
        }
        String rating = "";
        if(!summary.rating.equals("0.0") && !summary.rating.equals("0") && !summary.rating.isEmpty()) {
            rating = String.format("%s / 10  ", summary.rating);
        }
        String runtime = "";
        if(!summary.runtime.equals("0") && !summary.runtime.isEmpty()) {
            runtime = String.format("%s min  ", summary.runtime);
        }
        String size = "";
        if(!movie.sizeHuman.isEmpty()) {
            size = movie.sizeHuman;
        }
        if(!runtime.isEmpty() && !size.isEmpty()) {
            runtime += "/ ";
        }

        String infoText = rating + year;
        String infoText2 = runtime + size;

        info.setText(infoText);
        info2.setText(infoText2);
    }

    private class Torrent2HttpTask extends AsyncTask<Void, Integer, TorrentFile> {